From 767233cea385b659ba25c642f6788a7234d21e7b Mon Sep 17 00:00:00 2001 From: Patrick Fic <> Date: Tue, 11 Aug 2020 16:42:26 -0700 Subject: [PATCH] Added navigation to application, internationalization, and sign in screen. --- .vscode/imexmobilesnippets.code-snippets | 51 +++ App.js | 61 ++- babel-translations.babel | 301 +++++++++++++ .../screen-job-detail.component.jsx | 10 + .../screen-job-list.component.jsx | 12 + .../screen-main/screen-main.component.jsx | 113 +++++ ...creen-messaging-conversation.component.jsx | 10 + .../screen-messaging-list.component.jsx | 10 + .../screen-settings.component.jsx | 15 + .../screen-sign-in.component.jsx | 101 +++++ .../sign-out-button.component.jsx | 24 + components/signin.component.jsx | 43 -- firebase/firebase.utils.js | 85 +--- package.json | 15 + translations/en-US/common.json | 36 ++ translations/es-MX/common.json | 36 ++ translations/fr-CA/common.json | 36 ++ translations/i18n.js | 46 ++ yarn.lock | 414 +++++++++++++++++- 19 files changed, 1258 insertions(+), 161 deletions(-) create mode 100644 .vscode/imexmobilesnippets.code-snippets create mode 100644 babel-translations.babel create mode 100644 components/screen-job-detail/screen-job-detail.component.jsx create mode 100644 components/screen-job-list/screen-job-list.component.jsx create mode 100644 components/screen-main/screen-main.component.jsx create mode 100644 components/screen-messaging-conversation/screen-messaging-conversation.component.jsx create mode 100644 components/screen-messaging-list/screen-messaging-list.component.jsx create mode 100644 components/screen-settings/screen-settings.component.jsx create mode 100644 components/screen-sign-in/screen-sign-in.component.jsx create mode 100644 components/sign-out-button/sign-out-button.component.jsx delete mode 100644 components/signin.component.jsx create mode 100644 translations/en-US/common.json create mode 100644 translations/es-MX/common.json create mode 100644 translations/fr-CA/common.json create mode 100644 translations/i18n.js diff --git a/.vscode/imexmobilesnippets.code-snippets b/.vscode/imexmobilesnippets.code-snippets new file mode 100644 index 0000000..396d589 --- /dev/null +++ b/.vscode/imexmobilesnippets.code-snippets @@ -0,0 +1,51 @@ +{ + // Place your bodyshop workspace snippets here. Each snippet is defined under a snippet name and has a scope, prefix, body and + // description. Add comma separated ids of the languages where the snippet is applicable in the scope field. If scope + // is left empty or omitted, the snippet gets applied to all languages. The prefix is what is + // used to trigger the snippet and the body will be expanded and inserted. Possible variables are: + // $1, $2 for tab stops, $0 for the final cursor position, and ${1:label}, ${2:another} for placeholders. + // Placeholders with the same ids are connected. + // Example: + // "Print to console": { + // "scope": "javascript,typescript", + // "prefix": "log", + // "body": [ + // "console.log('$1');", + // "$2" + // ], + // "description": "Log output to console" + // } + "Const T useTranslation": { + "prefix": "ttt", + "body": ["const { t } = useTranslation();"], + "description": "Use Translation Destructing." + }, + " useTranslation import": { + "prefix": "tti", + "body": ["import { useTranslation } from \"react-i18next\";"], + "description": "Use Translation import." + }, + "Redux Setup": { + "prefix": "rdx", + "body": [ + "import { connect } from \"react-redux\";", + "import { createStructuredSelector } from \"reselect\";", + "const mapStateToProps = createStructuredSelector({", + " //currentUser: selectCurrentUser", + "});", + "const mapDispatchToProps = dispatch => ({", + " //setUserLanguage: language => dispatch(setUserLanguage(language))", + "});", + "export default connect (mapStateToProps,mapDispatchToProps)();" + ], + "description": "General Redux." + }, + " Apollo Loading Error Handling import": { + "prefix": "ale", + "body": [ + "if (loading) return ;", + "if (error) return ;" + ], + "description": "Apollo Loading Error Handling import." + } +} diff --git a/App.js b/App.js index ceb523c..c9bc9f9 100644 --- a/App.js +++ b/App.js @@ -1,31 +1,44 @@ -import { StatusBar } from "expo-status-bar"; +import { Ionicons } from "@expo/vector-icons"; +import { AppLoading } from "expo"; +import * as Font from "expo-font"; import React from "react"; -import { - SafeAreaView, - StatusBar as rnStatusBar, - StyleSheet, - Text, - View, -} from "react-native"; -import { store, persistor } from "./redux/store"; +import { StatusBar as rnStatusBar, StyleSheet } from "react-native"; import { Provider } from "react-redux"; import { PersistGate } from "redux-persist/integration/react"; -import SignIn from "./components/signin.component"; +import ScreenMainComponent from "./components/screen-main/screen-main.component"; +import { persistor, store } from "./redux/store"; +import "./translations/i18n"; -export default function App() { - return ( - - - - - Open up App.js to start working on your app! ttt - - - - - - - ); +export default class App extends React.Component { + constructor(props) { + super(props); + this.state = { + isReady: false, + }; + } + + async componentDidMount() { + await Font.loadAsync({ + Roboto: require("native-base/Fonts/Roboto.ttf"), + Roboto_medium: require("native-base/Fonts/Roboto_medium.ttf"), + ...Ionicons.font, + }); + this.setState({ isReady: true }); + } + + render() { + if (!this.state.isReady) { + return ; + } + + return ( + + + + + + ); + } } const styles = StyleSheet.create({ diff --git a/babel-translations.babel b/babel-translations.babel new file mode 100644 index 0000000..5a0bee0 --- /dev/null +++ b/babel-translations.babel @@ -0,0 +1,301 @@ + + + + i18next + babel-translations.babel + . + + + + + common + + + translation + + + general + + + actions + + + signout + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + + + + + + + joblist + + + labels + + + activejobs + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + + + + + titles + + + jobtab + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + + + + + + + messaging + + + titles + + + messagingtab + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + + + + + + + settings + + + titles + + + settings + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + + + + + + + signin + + + actions + + + signin + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + + + + + fields + + + email + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + + + password + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + + + + + + + + + + + + + false + + + en-US + + translations/en-US + + + es-MX + + translations/es-MX + + + fr-CA + + translations/fr-CA + + + + + translations/en-US + + + translations/es-MX + + + translations/fr-CA + + + + true + + '%1' + { this.props.t('%1') } + { t('%1') } + + + en-US + + tab + namespaced-json + + diff --git a/components/screen-job-detail/screen-job-detail.component.jsx b/components/screen-job-detail/screen-job-detail.component.jsx new file mode 100644 index 0000000..a4ddfc6 --- /dev/null +++ b/components/screen-job-detail/screen-job-detail.component.jsx @@ -0,0 +1,10 @@ +import React from "react"; +import { View, Text } from "react-native"; + +export default function ScreenJobDetail({ navigation, ...restProps }) { + return ( + + The is the detail of the job. + + ); +} diff --git a/components/screen-job-list/screen-job-list.component.jsx b/components/screen-job-list/screen-job-list.component.jsx new file mode 100644 index 0000000..5f9b678 --- /dev/null +++ b/components/screen-job-list/screen-job-list.component.jsx @@ -0,0 +1,12 @@ +import React from "react"; +import { View, Text } from "react-native"; +import { useTranslation } from "react-i18next"; +export default function ScreenJobList({ navigation }) { + const { t } = useTranslation(); + return ( + + This is the Job List. + {t("joblist.labels.activejobs")} + + ); +} diff --git a/components/screen-main/screen-main.component.jsx b/components/screen-main/screen-main.component.jsx new file mode 100644 index 0000000..d38d125 --- /dev/null +++ b/components/screen-main/screen-main.component.jsx @@ -0,0 +1,113 @@ +import { createBottomTabNavigator } from "@react-navigation/bottom-tabs"; +import { NavigationContainer } from "@react-navigation/native"; +import { createStackNavigator } from "@react-navigation/stack"; +import { createDrawerNavigator } from "@react-navigation/drawer"; +import i18n from "i18next"; +import React from "react"; +import { useTranslation } from "react-i18next"; +import { StatusBar as rnStatusBar, StyleSheet } from "react-native"; +import { connect } from "react-redux"; +import { createStructuredSelector } from "reselect"; +import { emailSignInStart, signOutStart } from "../../redux/user/user.actions"; +import { + selectBodyshop, + selectCurrentUser, +} from "../../redux/user/user.selectors"; +import ScreenJobDetail from "../screen-job-detail/screen-job-detail.component"; +import ScreenJobList from "../screen-job-list/screen-job-list.component"; +import ScreenMessagingConversation from "../screen-messaging-conversation/screen-messaging-conversation.component"; +import ScreenMessagingList from "../screen-messaging-list/screen-messaging-list.component"; +import ScreenSignIn from "../screen-sign-in/screen-sign-in.component"; +import ScreenSettingsComponent from "../screen-settings/screen-settings.component"; +const JobStack = createStackNavigator(); +const MessagingStack = createStackNavigator(); +const BottomTabs = createBottomTabNavigator(); +const Drawer = createDrawerNavigator(); + +const mapStateToProps = createStructuredSelector({ + bodyshop: selectBodyshop, + currentUser: selectCurrentUser, +}); + +const mapDispatchToProps = (dispatch) => ({ + emailSignInStart: (email, password) => + dispatch(emailSignInStart({ email, password })), + signOutStart: () => dispatch(signOutStart()), +}); + +const JobStackNavigator = () => ( + + ({ + title: `${i18n.t("joblist.labels.activejobs")} ${ + JSON.stringify(route.params) | "X" + }`, + })} + component={ScreenJobList} + /> + + +); + +const MessagingStackNavigator = () => ( + + + + +); + +const BottomTabsNavigator = () => ( + + + + +); + +const DrawerNavigator = () => ( + + + + +); + +export function ScreenMainComponent({ currentUser }) { + const { t } = useTranslation(); + return ( + + {currentUser.authorized ? : } + + ); +} +export default connect( + mapStateToProps, + mapDispatchToProps +)(ScreenMainComponent); + +const styles = StyleSheet.create({ + container: { + flex: 1, + backgroundColor: "#fff", + alignItems: "center", + justifyContent: "center", + paddingTop: Platform.OS === "android" ? rnStatusBar.currentHeight : 0, + }, +}); diff --git a/components/screen-messaging-conversation/screen-messaging-conversation.component.jsx b/components/screen-messaging-conversation/screen-messaging-conversation.component.jsx new file mode 100644 index 0000000..feeac47 --- /dev/null +++ b/components/screen-messaging-conversation/screen-messaging-conversation.component.jsx @@ -0,0 +1,10 @@ +import React from "react"; +import { View, Text } from "react-native"; + +export default function ScreenMessagingConversation({ navigation }) { + return ( + + The detailed conversation + + ); +} diff --git a/components/screen-messaging-list/screen-messaging-list.component.jsx b/components/screen-messaging-list/screen-messaging-list.component.jsx new file mode 100644 index 0000000..069ff23 --- /dev/null +++ b/components/screen-messaging-list/screen-messaging-list.component.jsx @@ -0,0 +1,10 @@ +import React from "react"; +import { View, Text } from "react-native"; + +export default function ScreenMessagingList() { + return ( + + A list of conversations. + + ); +} diff --git a/components/screen-settings/screen-settings.component.jsx b/components/screen-settings/screen-settings.component.jsx new file mode 100644 index 0000000..4f7a784 --- /dev/null +++ b/components/screen-settings/screen-settings.component.jsx @@ -0,0 +1,15 @@ +import React from "react"; +import { View, Text, SafeAreaView, Button } from "react-native"; +import SignOutButton from "../sign-out-button/sign-out-button.component"; +import { purgeStoredState } from "redux-persist"; +export default function ScreenSettingsComponent() { + return ( + + + The settings Screen + + + + + )} + + + + ); +} + +const styles = StyleSheet.create({ + contentContainer: { + justifyContent: "center", + flex: 1, + }, + content: { + paddingBottom: 150, + // flex: 1, + // backgroundColor: "#fff", + // alignItems: "center", + //justifyContent: "space-between", + // //justifyContent: "center", + }, +}); + +export default connect(mapStateToProps, mapDispatchToProps)(SignIn); diff --git a/components/sign-out-button/sign-out-button.component.jsx b/components/sign-out-button/sign-out-button.component.jsx new file mode 100644 index 0000000..86a23f2 --- /dev/null +++ b/components/sign-out-button/sign-out-button.component.jsx @@ -0,0 +1,24 @@ +import React from "react"; +import { useTranslation } from "react-i18next"; +import { Button } from "react-native"; +import { connect } from "react-redux"; +import { createStructuredSelector } from "reselect"; +import { signOutStart } from "../../redux/user/user.actions"; +const mapStateToProps = createStructuredSelector({ + //currentUser: selectCurrentUser +}); +const mapDispatchToProps = (dispatch) => ({ + //setUserLanguage: language => dispatch(setUserLanguage(language)) + signOutStart: () => dispatch(signOutStart()), +}); + +export function SignOutButton({ signOutStart }) { + const { t } = useTranslation(); + return ( +