diff --git a/.eslintrc.json b/.eslintrc.json
index ef8ecd6db87afabfe4808b27a63635891daba7fe..fabd327f7079220147102f08fc9ba668b2a29a0e 100644
--- a/.eslintrc.json
+++ b/.eslintrc.json
@@ -23,6 +23,7 @@
},
"plugins": ["react", "@typescript-eslint", "prettier"],
"rules": {
+ "linebreak-style": "off",
"func-names": "off",
"max-len": "error",
"no-console": "off",
diff --git a/src/SampleGroups.ts b/src/SampleGroups.ts
new file mode 100644
index 0000000000000000000000000000000000000000..07475e9069f58eb3cd7f878eb2cd8a5ba5fd3ca0
--- /dev/null
+++ b/src/SampleGroups.ts
@@ -0,0 +1,67 @@
+import { Group } from './store/groups/GroupState';
+
+export const sampleGroups: Group[] = [
+ {
+ groupId: '0',
+ groupName: 'School Squad',
+ memberList: [
+ {
+ userId: 'will.brown',
+ permissions: { admin: true },
+ },
+ {
+ userId: 'jayson',
+ permissions: { admin: false },
+ },
+ {
+ userId: 'krisztian',
+ permissions: { admin: false },
+ },
+ ],
+ cacheIdList: [
+ '1',
+ '2',
+ ],
+ },
+ {
+ groupId: '1',
+ groupName: 'Cool Club',
+ memberList: [
+ {
+ userId: 'will.brown',
+ permissions: { admin: true },
+ },
+ {
+ userId: 'krisztian',
+ permissions: { admin: false },
+ },
+ {
+ userId: 'jason',
+ permissions: { admin: false },
+ },
+ {
+ userId: 'milan.digiuseppe',
+ permissions: { admin: false },
+ },
+ {
+ userId: 'roxy.the.dog',
+ permissions: { admin: false },
+ },
+ {
+ userId: 'clifford.the.big.dog',
+ permissions: { admin: false },
+ },
+ {
+ userId: 'dogmeat',
+ permissions: { admin: false },
+ },
+ {
+ userId: 'epic.gamer.cool.dude',
+ permissions: { admin: false },
+ },
+ ],
+ cacheIdList: [
+ '3',
+ ],
+ },
+];
diff --git a/src/navigation/HomeNavigator.tsx b/src/navigation/HomeNavigator.tsx
index c43e608a283e7c624cf57aaf6dde7f954a41805f..3f7b8d209c7cf736c2fb37a9106ef33a0dee34df 100644
--- a/src/navigation/HomeNavigator.tsx
+++ b/src/navigation/HomeNavigator.tsx
@@ -8,6 +8,7 @@ import SavedListScreen from '../screens/SavedListScreen';
import CacheDetailScreen, { NavParams } from '../screens/CacheDetailScreen';
import RevisitCacheScreen from '../screens/RevisitCacheScreen';
import DevScreen from '../screens/DevScreen';
+import GroupScreen from '../screens/GroupScreen';
const Stack = createStackNavigator();
const HomeNavigator = () => (
@@ -23,7 +24,7 @@ const HomeNavigator = () => (
(
name={'Dev'}
component={DevScreen}
/>
+
);
diff --git a/src/screens/GroupScreen.tsx b/src/screens/GroupScreen.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..f308dd18cd48336f50b005aa591257e921ac8ef2
--- /dev/null
+++ b/src/screens/GroupScreen.tsx
@@ -0,0 +1,146 @@
+import React from 'react';
+import { useSelector } from 'react-redux';
+import { useRoute, useNavigation } from '@react-navigation/native';
+
+import {
+ View, StyleSheet, FlatList, Text,
+} from 'react-native';
+
+
+import {
+ Avatar, ListItem, Icon,
+} from 'react-native-elements';
+import CacheListItem from '../components/CacheListItem';
+import { Cache } from '../store/caches/CachesState';
+
+
+import GeoText from '../components/GeoText';
+import theme from '../theme';
+
+import {
+ getUserName,
+ getUserImageUrl,
+} from '../store/auth/AuthSelectors';
+import { getGroupMemgers, getGroupCaches, getGroup } from '../store/groups/GroupSelectors';
+import { Membership } from '../store/groups/GroupState';
+
+const styles = StyleSheet.create({
+ avatar: {
+ backgroundColor: theme.colors.mediumgray,
+ marginTop: theme.spacing.medium,
+ },
+});
+
+const renderMember = (item: { item: Membership }) => {
+ const member = item.item;
+ return (
+
+ );
+};
+
+const renderCache = (item: {item: Cache}) => {
+ const {
+ id,
+ found,
+ name,
+ message,
+ isUserCreated,
+
+ type,
+ game,
+ foundReverseGeocode,
+ imageUri,
+ } = item.item;
+ return (
+
+ );
+};
+
+const GroupScreen = () => {
+ const { params } = useRoute();
+ const userName = useSelector(getUserName);
+ const userImageUrl = useSelector(getUserImageUrl);
+
+
+ const { groupId } = params;
+ const group = useSelector(getGroup(groupId));
+ const memberList = useSelector(getGroupMemgers(groupId));
+ const cacheList = useSelector(getGroupCaches(groupId));
+
+ return (
+
+
+
+
+
+
+
+ cache.id}
+ />
+
+
+
+
+
+ member.userId}
+ />
+
+
+ );
+};
+
+export default GroupScreen;
diff --git a/src/screens/MainDrawer.tsx b/src/screens/MainDrawer.tsx
index 32c963baa44fa0d67421ae68265054a5675408ea..e032b9d92fc3c864b4c2be779e4b5b91750666ae 100644
--- a/src/screens/MainDrawer.tsx
+++ b/src/screens/MainDrawer.tsx
@@ -1,9 +1,12 @@
import React, { useCallback, useMemo } from 'react';
-import { View, StyleSheet } from 'react-native';
-import { Avatar, ListItem, Icon } from 'react-native-elements';
+import { View, StyleSheet, Group } from 'react-native';
+import {
+ Avatar, ListItem, Icon,
+} from 'react-native-elements';
import { useSelector, useDispatch } from 'react-redux';
import { useNavigation } from '@react-navigation/native';
import { getUserImageUrl, getUserName } from '../store/auth/AuthSelectors';
+import { getGroups } from '../store/groups/GroupSelectors';
import theme from '../theme';
import GeoText from '../components/GeoText';
import GeoButton from '../components/GeoButton';
@@ -40,6 +43,7 @@ const MainDrawer: React.FC = ({ onClose }) => {
const { navigate } = useNavigation();
const userImageUrl = useSelector(getUserImageUrl);
const userName = useSelector(getUserName);
+ const groups = useSelector(getGroups);
const onSettingsPress = useCallback(() => {
onClose();
@@ -55,6 +59,11 @@ const MainDrawer: React.FC = ({ onClose }) => {
dispatch(signOutAsync());
}, [dispatch, onClose]);
+ const onGroupSettings = useCallback(() => {
+ // onClose();
+ navigate('Group', {});
+ }, [onClose, navigate]);
+
const items: ActionItem[] = useMemo(() => ([
{
icon: 'user-edit',
@@ -73,6 +82,7 @@ const MainDrawer: React.FC = ({ onClose }) => {
},
]), [onSettingsPress, onDevPress]);
+
return (
@@ -104,6 +114,34 @@ const MainDrawer: React.FC = ({ onClose }) => {
onPress={item.onPress}
/>
))}
+
+
+ {
+ groups.map((group) => (
+ navigate('Group', { groupId: group.groupId })}
+ />
+ ))
+ }
+
diff --git a/src/store/RootReducer.ts b/src/store/RootReducer.ts
index f58382c825f661486b665e0d37b203bde09cb3d7..27db24d9404f62261b76a554d6ad59a5fb03978e 100644
--- a/src/store/RootReducer.ts
+++ b/src/store/RootReducer.ts
@@ -3,12 +3,14 @@ import authSlice from './auth/AuthSlice';
import cachesSlice from './caches/CachesSlice';
import locationSlice from './location/LocationSlice';
import pendingCacheSlice from './pendingNewCache/PendingCacheSlice';
+import groupsSlice from './groups/GroupSlice';
const rootReducer = combineReducers({
auth: authSlice.reducer,
caches: cachesSlice.reducer,
location: locationSlice.reducer,
pendingCache: pendingCacheSlice.reducer,
+ groups: groupsSlice.reducer,
});
export type RootState = ReturnType;
diff --git a/src/store/groups/GroupActions.ts b/src/store/groups/GroupActions.ts
new file mode 100644
index 0000000000000000000000000000000000000000..d080d24f6d0839b2b56f18e21055e6cacddb1fb9
--- /dev/null
+++ b/src/store/groups/GroupActions.ts
@@ -0,0 +1,2 @@
+import { Dispatch } from '@reduxjs/toolkit';
+import { LatLng } from 'react-native-maps';
diff --git a/src/store/groups/GroupSelectors.ts b/src/store/groups/GroupSelectors.ts
new file mode 100644
index 0000000000000000000000000000000000000000..de628bb4064cd8aee82d461682c0516c850863bd
--- /dev/null
+++ b/src/store/groups/GroupSelectors.ts
@@ -0,0 +1,30 @@
+import { createSelector } from '@reduxjs/toolkit';
+import { State } from 'react-native-gesture-handler';
+import { getDiscoveredCaches } from '../caches/CachesSelectors';
+import { RootState } from '../RootReducer';
+
+export const getGroups = (state: RootState) => Object.values(state.groups.groups);
+
+export const getGroup = (id: string) => createSelector(
+ [getGroups],
+ (groups) => groups[id],
+);
+
+export const getGroupMemgers = (id: string) => createSelector(
+ [getGroups],
+ (groups) => groups[id].memberList,
+);
+
+export const getGroupCaches = (id: string) => createSelector(
+ [
+ getGroups,
+ (state) => state.caches.saved,
+ ],
+ (groups, caches) => {
+ const result: Cache[] = [];
+ for (const c in Object.values(groups[id].cacheIdList)) {
+ result.push(caches[c]);
+ }
+ return result;
+ },
+);
diff --git a/src/store/groups/GroupSlice.ts b/src/store/groups/GroupSlice.ts
new file mode 100644
index 0000000000000000000000000000000000000000..58a09f7cd7fab36b64a160617c32b83d0111cc24
--- /dev/null
+++ b/src/store/groups/GroupSlice.ts
@@ -0,0 +1,35 @@
+import { createSlice } from '@reduxjs/toolkit';
+import { sampleCaches } from '../../SampleCaches';
+import { CachesState } from './CachesState';
+import { sampleGroups } from '../../SampleGroups';
+import { GroupState } from './GroupState';
+
+const groupsSlice = createSlice({
+ name: 'groups',
+ initialState: {
+ groups: {
+ [sampleGroups[0].groupId]: sampleGroups[0],
+ [sampleGroups[1].groupId]: sampleGroups[1],
+ },
+ } as GroupState,
+ reducers: {
+ /*
+ addSaved(state, action) {
+ const cache = action.payload;
+ state.saved[cache.id] = cache;
+ },
+ removeSaved(state, action) {
+ delete state.saved[action.payload];
+ },
+ addDiscovered(state, action) {
+ const cache = action.payload;
+ state.discovered[cache.id] = cache;
+ },
+ removeDiscovered(state, action) {
+ delete state.discovered[action.payload];
+ },
+ */
+ },
+});
+
+export default groupsSlice;
diff --git a/src/store/groups/GroupState.ts b/src/store/groups/GroupState.ts
new file mode 100644
index 0000000000000000000000000000000000000000..a690d5aeafd35b6e4d182be2706e46b2f4f1361d
--- /dev/null
+++ b/src/store/groups/GroupState.ts
@@ -0,0 +1,25 @@
+import { User } from 'firebase';
+import { UserInterfaceIdiom } from 'expo-constants';
+
+
+export interface GroupPermissions {
+ admin: boolean;
+}
+
+export interface Membership {
+ userId: string; // correct type ??
+ permissions: GroupPermissions;
+}
+
+export interface Group {
+ groupId: string;
+ groupName: string;
+ memberList: Membership[];
+ cacheIdList: string[]; // just reference caches.. don't need to duplicate info
+}
+
+export interface GroupState {
+ groups: {
+ [id: string]: Group;
+ };
+}