diff --git a/app/mobile/src/context/useCardContext.hook.js b/app/mobile/src/context/useCardContext.hook.js
index 00c696db..867e3638 100644
--- a/app/mobile/src/context/useCardContext.hook.js
+++ b/app/mobile/src/context/useCardContext.hook.js
@@ -29,6 +29,7 @@ import { removeContactChannelTopic } from 'api/removeContactChannelTopic';
export function useCardContext() {
const [state, setState] = useState({
cards: new Map(),
+ requestRevision: null,
});
const store = useContext(StoreContext);
const upload = useContext(UploadContext);
@@ -356,6 +357,8 @@ export function useCardContext() {
setSession: async (access) => {
const { guid, server, appToken } = access;
cards.current = new Map();
+ const status = await store.actions.getCardRequestStatus(guid);
+ updateState({ requestRevision: status.revision });
const cardItems = await store.actions.getCardItems(guid);
for (item of cardItems) {
cards.current.set(item.cardId, { ...item, channels: new Map() });
@@ -370,6 +373,11 @@ export function useCardContext() {
curRevision.current = revision;
session.current = access;
},
+ setRequestRevision: async (revision) => {
+ const { guid } = session.current
+ await store.actions.setCardRequestStatus(guid, { revision });
+ updateState({ requestRevision: revision });
+ },
clearSession: () => {
session.current = {};
updateState({ account: null });
diff --git a/app/mobile/src/context/useStoreContext.hook.js b/app/mobile/src/context/useStoreContext.hook.js
index 55ee5f07..2b9b7aa3 100644
--- a/app/mobile/src/context/useStoreContext.hook.js
+++ b/app/mobile/src/context/useStoreContext.hook.js
@@ -44,6 +44,14 @@ export function useStoreContext() {
const dataId = `${guid}_profile`;
await db.current.executeSql("INSERT OR REPLACE INTO app (key, value) values (?, ?);", [dataId, encodeObject(profile)]);
},
+ getCardRequestStatus: async (guid) => {
+ const dataId = `${guid}_card_status`;
+ return await getAppValue(db.current, dataId, {});
+ },
+ setCardRequestStatus: async (guid, status) => {
+ const dataId = `${guid}_card_status`;
+ await db.current.executeSql("INSERT OR REPLACE INTO app (key, value) values (?, ?);", [dataId, encodeObject(status)]);
+ },
getProfileRevision: async (guid) => {
const dataId = `${guid}_profileRevision`;
return await getAppValue(db.current, dataId, null);
diff --git a/app/mobile/src/session/Session.jsx b/app/mobile/src/session/Session.jsx
index 215a0ef3..4910c4e5 100644
--- a/app/mobile/src/session/Session.jsx
+++ b/app/mobile/src/session/Session.jsx
@@ -23,6 +23,7 @@ import { useChannels } from './channels/useChannels.hook';
import { CommonActions } from '@react-navigation/native';
import { ConversationContext } from 'context/ConversationContext';
import { ProfileIcon } from './profileIcon/ProfileIcon';
+import { CardsIcon } from './cardsIcon/CardsIcon';
const ConversationStack = createStackNavigator();
const ProfileStack = createStackNavigator();
@@ -201,8 +202,8 @@ export function Session() {
Profile
-
- Contacts
+
+ Contacts
@@ -337,6 +338,8 @@ export function Session() {
);
}
+ const [cardsActive, setCardsActive] = useState(false);
+
return (
{ state.tabbed === false && (
@@ -349,6 +352,7 @@ export function Session() {
)}
{ state.tabbed === true && (
setCardsActive(e?.data?.state?.index === 2) }}
screenOptions={({ route }) => ({
tabBarStyle: styles.tabBar,
headerShown: false,
@@ -360,7 +364,7 @@ export function Session() {
return ;
}
if (route.name === 'Contacts') {
- return ;
+ return ;
}
},
tabBarShowLabel: false,
diff --git a/app/mobile/src/session/cardsIcon/CardsIcon.jsx b/app/mobile/src/session/cardsIcon/CardsIcon.jsx
new file mode 100644
index 00000000..30264b33
--- /dev/null
+++ b/app/mobile/src/session/cardsIcon/CardsIcon.jsx
@@ -0,0 +1,19 @@
+import { View } from 'react-native';
+import { useCardsIcon } from './useCardsIcon.hook';
+import { styles } from './CardsIcon.styled';
+import Ionicons from '@expo/vector-icons/AntDesign';
+
+export function CardsIcon({ size, color, active }) {
+
+ const { state, actions } = useCardsIcon(active);
+
+ return (
+
+
+ { state.curRevision !== state.setRevision && (
+
+ )}
+
+ );
+}
+
diff --git a/app/mobile/src/session/cardsIcon/CardsIcon.styled.js b/app/mobile/src/session/cardsIcon/CardsIcon.styled.js
new file mode 100644
index 00000000..7d9030d6
--- /dev/null
+++ b/app/mobile/src/session/cardsIcon/CardsIcon.styled.js
@@ -0,0 +1,14 @@
+import { StyleSheet } from 'react-native';
+import { Colors } from 'constants/Colors';
+
+export const styles = StyleSheet.create({
+ requested: {
+ width: 8,
+ height: 8,
+ borderRadius: 4,
+ backgroundColor: Colors.pending,
+ position: 'absolute',
+ right: 0,
+ bottom: 0,
+ },
+});
diff --git a/app/mobile/src/session/cardsIcon/useCardsIcon.hook.js b/app/mobile/src/session/cardsIcon/useCardsIcon.hook.js
new file mode 100644
index 00000000..054aa28d
--- /dev/null
+++ b/app/mobile/src/session/cardsIcon/useCardsIcon.hook.js
@@ -0,0 +1,43 @@
+import { useState, useEffect, useContext } from 'react';
+import { CardContext } from 'context/CardContext';
+
+export function useCardsIcon(active) {
+
+ const [state, setState] = useState({
+ curRevision: null,
+ setRevision: null,
+ });
+
+ const card = useContext(CardContext);
+
+ const updateState = (value) => {
+ setState((s) => ({ ...s, ...value }));
+ }
+
+ useEffect(() => {
+ if (active && state.curRevision) {
+ card.actions.setRequestRevision(state.curRevision);
+ }
+ }, [active]);
+
+ useEffect(() => {
+ let revision;
+ card.state.cards.forEach((contact) => {
+ if (contact?.detail?.status === 'pending' || contact?.detail?.status === 'requested') {
+ if (!revision || contact.detailRevision > revision) {
+ revision = contact.detailRevision;
+ }
+ }
+ });
+ if (active && revision !== state.setRevision) {
+ card.actions.setRequestRevision(state.curRevision);
+ }
+ updateState({ setRevision: card.state.requestRevision, curRevision: revision });
+
+ }, [card]);
+
+ const actions = {};
+
+ return { state, actions };
+}
+