Browse Source

FEATURE| Get items from firebase| Redux store firebase items

merge-requests/7/head
JetUp 2 years ago
parent
commit
0f0b09871a
  1. 5
      App.tsx
  2. 8
      ReactotronConfig.js
  3. 117
      package-lock.json
  4. 1
      package.json
  5. 5
      src/module/package/components/packages-item.component.tsx
  6. 53
      src/module/root/navigations-groups/on-boardings-group.tsx
  7. 5
      src/module/root/screens/loading-screen.tsx
  8. 4
      src/module/root/screens/questions.tsx
  9. 65
      src/module/services/game-items/game-items-slice.ts
  10. 32
      src/module/shared/components/question-block/question-block.tsx
  11. 7
      src/module/shared/interfaces/game-item.ts
  12. 13
      src/store/store.ts

5
App.tsx

@ -4,6 +4,11 @@ import {Navigation} from './src/module/root'; @@ -4,6 +4,11 @@ import {Navigation} from './src/module/root';
import './src/i18n/index';
import {Provider} from 'react-redux';
import { store } from './src/store/store';
if(__DEV__) {
import('./ReactotronConfig').then(() => console.log('Reactotron Configured'))
}
const App = () => {
useEffect(() => {
SplashScreen.hide();

8
ReactotronConfig.js

@ -0,0 +1,8 @@ @@ -0,0 +1,8 @@
import AsyncStorage from '@react-native-async-storage/async-storage'
import Reactotron from 'reactotron-react-native'
Reactotron
.setAsyncStorageHandler(AsyncStorage) // AsyncStorage would either come from `react-native` or `@react-native-community/async-storage` depending on where you get it from
.configure() // controls connection & communication settings
.useReactNative() // add all built-in react native plugins
.connect() // let's connect!

117
package-lock.json generated

@ -48,6 +48,7 @@ @@ -48,6 +48,7 @@
"jest": "^26.6.3",
"metro-react-native-babel-preset": "^0.66.2",
"react-test-renderer": "17.0.2",
"reactotron-react-native": "^5.0.3",
"typescript": "^4.4.4"
}
},
@ -12145,6 +12146,12 @@ @@ -12145,6 +12146,12 @@
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz",
"integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q=="
},
"node_modules/mitt": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/mitt/-/mitt-1.1.3.tgz",
"integrity": "sha512-mUDCnVNsAi+eD6qA0HkRkwYczbLHJ49z17BGe2PYRhZL4wpZUFZGJHU7/5tmvohoma+Hdn0Vh/oJTiPEmgSruA==",
"dev": true
},
"node_modules/mixin-deep": {
"version": "1.3.2",
"resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz",
@ -13443,6 +13450,17 @@ @@ -13443,6 +13450,17 @@
"nullthrows": "^1.1.1"
}
},
"node_modules/react-native-flipper": {
"version": "0.164.0",
"resolved": "https://registry.npmjs.org/react-native-flipper/-/react-native-flipper-0.164.0.tgz",
"integrity": "sha512-iJhIe3rqx6okuzBp4AJsTa2b8VRAOGzoLRFx/4HGbaGvu8AurZjz8TTQkhJsRma8dsHN2b6KKZPvGGW3wdWzvA==",
"dev": true,
"optional": true,
"peerDependencies": {
"react": "^16.8.0 || ^17.0.0 || ^18.0.0",
"react-native": ">0.62.0"
}
},
"node_modules/react-native-gesture-handler": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/react-native-gesture-handler/-/react-native-gesture-handler-2.5.0.tgz",
@ -14038,6 +14056,47 @@ @@ -14038,6 +14056,47 @@
"react": "17.0.2"
}
},
"node_modules/reactotron-core-client": {
"version": "2.8.10",
"resolved": "https://registry.npmjs.org/reactotron-core-client/-/reactotron-core-client-2.8.10.tgz",
"integrity": "sha512-SYRO4OCutJzfWMnaULUGVyETZnMDCU5ECNflXyM3Z5Gnfxp/wV6d7jYonhfxHdpU/aGb4Eg15C22myOCXSu6HQ==",
"dev": true
},
"node_modules/reactotron-react-native": {
"version": "5.0.3",
"resolved": "https://registry.npmjs.org/reactotron-react-native/-/reactotron-react-native-5.0.3.tgz",
"integrity": "sha512-uUQ074uw3I9X/pc7FBgrrwrFzfwXDKlxzuekNjzspZz9Y0qVLX1cAm9GTC0ZPsZRvY5wDPY/Il7XfV1YeVSDxA==",
"dev": true,
"dependencies": {
"mitt": "1.1.3",
"query-string": "6.10.1",
"reactotron-core-client": "2.8.10",
"rn-host-detect": "1.2.0"
},
"optionalDependencies": {
"react-native-flipper": "^0.164.0"
},
"peerDependencies": {
"react-native": ">=0.40.0"
}
},
"node_modules/reactotron-react-native/node_modules/query-string": {
"version": "6.10.1",
"resolved": "https://registry.npmjs.org/query-string/-/query-string-6.10.1.tgz",
"integrity": "sha512-SHTUV6gDlgMXg/AQUuLpTiBtW/etZ9JT6k6RCtCyqADquApLX0Aq5oK/s5UeTUAWBG50IExjIr587GqfXRfM4A==",
"dev": true,
"dependencies": {
"decode-uri-component": "^0.2.0",
"split-on-first": "^1.0.0",
"strict-uri-encode": "^2.0.0"
},
"engines": {
"node": ">=6"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/read-pkg": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz",
@ -14470,6 +14529,12 @@ @@ -14470,6 +14529,12 @@
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/rn-host-detect": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/rn-host-detect/-/rn-host-detect-1.2.0.tgz",
"integrity": "sha512-btNg5kzHcjZZ7t7mvvV/4wNJ9e3MPgrWivkRgWURzXL0JJ0pwWlU4zrbmdlz3HHzHOxhBhHB4D+/dbMFfu4/4A==",
"dev": true
},
"node_modules/rsvp": {
"version": "4.8.5",
"resolved": "https://registry.npmjs.org/rsvp/-/rsvp-4.8.5.tgz",
@ -26011,6 +26076,12 @@ @@ -26011,6 +26076,12 @@
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz",
"integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q=="
},
"mitt": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/mitt/-/mitt-1.1.3.tgz",
"integrity": "sha512-mUDCnVNsAi+eD6qA0HkRkwYczbLHJ49z17BGe2PYRhZL4wpZUFZGJHU7/5tmvohoma+Hdn0Vh/oJTiPEmgSruA==",
"dev": true
},
"mixin-deep": {
"version": "1.3.2",
"resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz",
@ -27167,6 +27238,14 @@ @@ -27167,6 +27238,14 @@
"nullthrows": "^1.1.1"
}
},
"react-native-flipper": {
"version": "0.164.0",
"resolved": "https://registry.npmjs.org/react-native-flipper/-/react-native-flipper-0.164.0.tgz",
"integrity": "sha512-iJhIe3rqx6okuzBp4AJsTa2b8VRAOGzoLRFx/4HGbaGvu8AurZjz8TTQkhJsRma8dsHN2b6KKZPvGGW3wdWzvA==",
"dev": true,
"optional": true,
"requires": {}
},
"react-native-gesture-handler": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/react-native-gesture-handler/-/react-native-gesture-handler-2.5.0.tgz",
@ -27404,6 +27483,38 @@ @@ -27404,6 +27483,38 @@
"scheduler": "^0.20.2"
}
},
"reactotron-core-client": {
"version": "2.8.10",
"resolved": "https://registry.npmjs.org/reactotron-core-client/-/reactotron-core-client-2.8.10.tgz",
"integrity": "sha512-SYRO4OCutJzfWMnaULUGVyETZnMDCU5ECNflXyM3Z5Gnfxp/wV6d7jYonhfxHdpU/aGb4Eg15C22myOCXSu6HQ==",
"dev": true
},
"reactotron-react-native": {
"version": "5.0.3",
"resolved": "https://registry.npmjs.org/reactotron-react-native/-/reactotron-react-native-5.0.3.tgz",
"integrity": "sha512-uUQ074uw3I9X/pc7FBgrrwrFzfwXDKlxzuekNjzspZz9Y0qVLX1cAm9GTC0ZPsZRvY5wDPY/Il7XfV1YeVSDxA==",
"dev": true,
"requires": {
"mitt": "1.1.3",
"query-string": "6.10.1",
"react-native-flipper": "^0.164.0",
"reactotron-core-client": "2.8.10",
"rn-host-detect": "1.2.0"
},
"dependencies": {
"query-string": {
"version": "6.10.1",
"resolved": "https://registry.npmjs.org/query-string/-/query-string-6.10.1.tgz",
"integrity": "sha512-SHTUV6gDlgMXg/AQUuLpTiBtW/etZ9JT6k6RCtCyqADquApLX0Aq5oK/s5UeTUAWBG50IExjIr587GqfXRfM4A==",
"dev": true,
"requires": {
"decode-uri-component": "^0.2.0",
"split-on-first": "^1.0.0",
"strict-uri-encode": "^2.0.0"
}
}
}
},
"read-pkg": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz",
@ -27738,6 +27849,12 @@ @@ -27738,6 +27849,12 @@
"glob": "^7.1.3"
}
},
"rn-host-detect": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/rn-host-detect/-/rn-host-detect-1.2.0.tgz",
"integrity": "sha512-btNg5kzHcjZZ7t7mvvV/4wNJ9e3MPgrWivkRgWURzXL0JJ0pwWlU4zrbmdlz3HHzHOxhBhHB4D+/dbMFfu4/4A==",
"dev": true
},
"rsvp": {
"version": "4.8.5",
"resolved": "https://registry.npmjs.org/rsvp/-/rsvp-4.8.5.tgz",

1
package.json

@ -55,6 +55,7 @@ @@ -55,6 +55,7 @@
"jest": "^26.6.3",
"metro-react-native-babel-preset": "^0.66.2",
"react-test-renderer": "17.0.2",
"reactotron-react-native": "^5.0.3",
"typescript": "^4.4.4"
},
"resolutions": {

5
src/module/package/components/packages-item.component.tsx

@ -4,6 +4,7 @@ import {StyleSheet, TouchableOpacity, View, Text} from 'react-native'; @@ -4,6 +4,7 @@ import {StyleSheet, TouchableOpacity, View, Text} from 'react-native';
import { useAppDispatch } from '../../../store/hooks';
import { nextStep, resetSteps } from '../../services/current-step/current-step-slice';
import { shuffleDares } from '../../services/dares/dares-slice';
import { shuffleItems } from '../../services/game-items/game-items-slice';
import { shuffleTruths } from '../../services/truths/truth-slice';
import {Icon, RouteKey} from '../../shared';
@ -29,11 +30,9 @@ export const PackagesItem: FC<IPackage> = ({ @@ -29,11 +30,9 @@ export const PackagesItem: FC<IPackage> = ({
const dispatch = useAppDispatch();
const play = () => {
console.log(title);
navigation.navigate(RouteKey.Package, {title});
dispatch(resetSteps());
dispatch(shuffleTruths());
dispatch(shuffleDares());
dispatch(shuffleItems());
}
return (

53
src/module/root/navigations-groups/on-boardings-group.tsx

@ -9,36 +9,55 @@ import {Questions} from '../screens/questions'; @@ -9,36 +9,55 @@ import {Questions} from '../screens/questions';
import {PrivacyPolicy} from '../../privacy-policy/screens/privacy-policy';
import {UseOfTerms} from '../../terms-of-use/screens/use-of-terms';
import firestore from '@react-native-firebase/firestore';
import AsyncStorage from '@react-native-async-storage/async-storage';
import { useAppDispatch, useAppSelector } from '../../../store/hooks';
import { fetchPostsAsync, selectPosts } from '../../services/game-items/game-items-slice';
// console.log(usersCollection);
const Stack = createNativeStackNavigator();
export const OnboardingGroup: FC = () => {
// const usersCollection = firestore()
// .collection('GameItems')
// .get()
// .then(querySnapshot => {
// querySnapshot.forEach(snapshot => {
// let data = snapshot.data();
// data.GameItems.map(item => console.log(item));
// });
// });
const getall = async () => {
const keys = await AsyncStorage.getAllKeys();
const result = await AsyncStorage.multiGet(keys);
console.log(result);
}
const submitPost = async () => {
firestore()
.collection('GameItems')
.add({
id: 6,
isDare: true,
en: 'Dare 3',
ua: 'Дія 3',
hi: 'हिमत 3'
})
.then(() => {})
.catch(error => console.log('Error in firebase'));
};
// submitPost();
getall();
const fetchPosts = async () => {
try {
firestore()
.collection('GameItems')
.get()
.then((querySnapshot) => {
querySnapshot.forEach(doc => {
const item = doc.data();
console.log(item);
})
}).catch((error) => {
console.log('Error in fetch: ', error);
})
} catch(error) {
console.log('Error in fetch: ', error);
}
}
// fetchPosts();
return (
<Stack.Navigator
screenOptions={{
headerShown: false,
}}
initialRouteName={RouteKey.LanguageSelect}>
initialRouteName={RouteKey.Loading}>
<Stack.Screen name={RouteKey.Questions} component={Questions} />
<Stack.Screen name={RouteKey.Package} component={Game} />
<Stack.Screen name={RouteKey.Onboarding} component={Onboarding} />

5
src/module/root/screens/loading-screen.tsx

@ -11,11 +11,15 @@ import AsyncStorage from '@react-native-async-storage/async-storage'; @@ -11,11 +11,15 @@ import AsyncStorage from '@react-native-async-storage/async-storage';
import {useNavigation, CommonActions} from '@react-navigation/native';
import {StorageKey, storageService} from '../../services/async-storage.service';
import { useTranslation } from 'react-i18next';
import { useAppDispatch } from '../../../store/hooks';
import { fetchPostsAsync } from '../../services/game-items/game-items-slice';
export const LoadingScreen = () => {
const {i18n} = useTranslation();
const navigate = useNavigation();
const dispatch = useAppDispatch();
const getLanguage = async () => {
const response = await AsyncStorage.getItem(StorageKey.Language);
return response;
@ -29,6 +33,7 @@ export const LoadingScreen = () => { @@ -29,6 +33,7 @@ export const LoadingScreen = () => {
const init = async () => {
let language = await getLanguage();
const isOnBoard = await getOnboardEnd();
dispatch(fetchPostsAsync());
if (language) {
i18n.changeLanguage(language);

4
src/module/root/screens/questions.tsx

@ -25,6 +25,7 @@ import { @@ -25,6 +25,7 @@ import {
} from '../../services/current-step/current-step-slice';
import {shuffleTruths} from '../../services/truths/truth-slice';
import {shuffleDares} from '../../services/dares/dares-slice';
import { shuffleItems } from '../../services/game-items/game-items-slice';
interface IProps extends IRouteParams {}
export const Questions: React.FC<IProps> = ({navigation, route}) => {
@ -44,8 +45,7 @@ export const Questions: React.FC<IProps> = ({navigation, route}) => { @@ -44,8 +45,7 @@ export const Questions: React.FC<IProps> = ({navigation, route}) => {
};
const refreshList = () => {
dispatch(shuffleTruths());
dispatch(shuffleDares());
dispatch(shuffleItems())
dispatch(resetSteps());
};

65
src/module/services/game-items/game-items-slice.ts

@ -0,0 +1,65 @@ @@ -0,0 +1,65 @@
import {createAsyncThunk, createSlice} from '@reduxjs/toolkit';
import {GameItem} from '../../shared/interfaces/game-item';
import firestore from '@react-native-firebase/firestore';
import {RootState} from '../../../store/store';
import { shuffle } from '../shuffle/shuffle';
export interface PostsState {
posts: GameItem[];
shuffled: GameItem[];
loaded: boolean;
hasError: boolean;
}
const initialState: PostsState = {
posts: [],
shuffled: [],
loaded: false,
hasError: false,
};
export const fetchPostsAsync = createAsyncThunk(
'posts/fetchPosts',
async () => {
const data = [] as GameItem[];
let querySnapshot = await firestore().collection('GameItems').get();
querySnapshot.forEach(doc => {
const item = doc.data();
data.push(item as GameItem);
});
return data;
},
);
export const postsSlice = createSlice({
name: 'posts',
initialState,
reducers: {
shuffleItems: state => {
state.shuffled = shuffle(state.posts);
},
},
extraReducers(builder) {
builder
.addCase(fetchPostsAsync.fulfilled, (state, action) => {
state.posts = action.payload;
state.hasError = false;
state.loaded = true;
})
.addCase(fetchPostsAsync.pending, state => {
state.loaded = false;
})
.addCase(fetchPostsAsync.rejected, state => {
state.hasError = true;
});
},
});
export const {shuffleItems} = postsSlice.actions;
export const selectPosts = (state: RootState) => state.gameItems.posts;
export const selectHasError = (state: RootState) => state.gameItems.hasError;
export const selectLoaded = (state: RootState) => state.gameItems.loaded;
export const selectShuffled = (state: RootState) => state.gameItems.shuffled;
export default postsSlice.reducer;

32
src/module/shared/components/question-block/question-block.tsx

@ -13,6 +13,9 @@ import { @@ -13,6 +13,9 @@ import {
shuffleTruths,
} from '../../../services/truths/truth-slice';
import {getShuffledDares, shuffleDares} from '../../../services/dares/dares-slice';
import { selectPosts, selectShuffled, shuffleItems } from '../../../services/game-items/game-items-slice';
import { useTranslation } from 'react-i18next';
import { GameItem } from '../../interfaces/game-item';
interface IProps {
isQuestions: boolean;
@ -21,21 +24,30 @@ interface IProps { @@ -21,21 +24,30 @@ interface IProps {
export const QuestionBlock: React.FC<IProps> = ({isQuestions}) => {
const navigation = useNavigation();
const dispatch = useAppDispatch();
const {i18n} = useTranslation();
const lang = i18n.language;
const currentStep = useAppSelector(getStep);
const shuffledTruths = useAppSelector(getShuffledTruths);
const shuffledDares = useAppSelector(getShuffledDares);
console.log(currentStep);
const gameItems = useAppSelector(selectShuffled);
const dares = gameItems.filter((dare) => dare.isDare);
const questions = gameItems.filter((question) => !question.isDare);
console.log(dares);
useEffect(() => {
if (currentStep >= shuffledTruths.length) {
if (currentStep >= questions.length) {
dispatch(resetSteps());
dispatch(shuffleTruths());
dispatch(shuffleItems());
}
if (currentStep >= shuffledDares.length) {
if (currentStep >= dares.length) {
dispatch(resetSteps());
dispatch(shuffleDares());
dispatch(shuffleItems());
}
}, [currentStep]);
@ -45,12 +57,12 @@ export const QuestionBlock: React.FC<IProps> = ({isQuestions}) => { @@ -45,12 +57,12 @@ export const QuestionBlock: React.FC<IProps> = ({isQuestions}) => {
<Image source={require('../../../../assets/image/magic-star.png')} />
</View>
<Text style={styles.text}>
{currentStep < shuffledTruths.length &&
{currentStep < questions.length &&
isQuestions &&
shuffledTruths[currentStep].question}
{currentStep < shuffledDares.length &&
questions[currentStep][lang as keyof GameItem]}
{currentStep < dares.length &&
!isQuestions &&
shuffledDares[currentStep].dare}
dares[currentStep][lang as keyof GameItem]}
</Text>
</View>
);

7
src/module/shared/interfaces/game-item.ts

@ -0,0 +1,7 @@ @@ -0,0 +1,7 @@
export interface GameItem {
id: number;
isDare: boolean;
en: string;
ua: string;
hi: string;
}

13
src/store/store.ts

@ -1,6 +1,7 @@ @@ -1,6 +1,7 @@
import { configureStore } from '@reduxjs/toolkit';
import { Action, configureStore, ThunkAction } from '@reduxjs/toolkit';
import currentStepSlice from '../module/services/current-step/current-step-slice';
import daresSlice from '../module/services/dares/dares-slice';
import postsSlice from '../module/services/game-items/game-items-slice';
import truthsSlice from '../module/services/truths/truth-slice';
export const store = configureStore({
@ -8,8 +9,16 @@ export const store = configureStore({ @@ -8,8 +9,16 @@ export const store = configureStore({
currentStep: currentStepSlice,
truth: truthsSlice,
dares: daresSlice,
gameItems: postsSlice,
},
});
export type AppDispatch = typeof store.dispatch;
export type RootState = ReturnType<typeof store.getState>;
export type RootState = ReturnType<typeof store.getState>;
export type AppThunk<ReturnType = void> = ThunkAction<
ReturnType,
RootState,
unknown,
Action<string>
>;
Loading…
Cancel
Save