2022-09-28 22:09:10 +00:00
|
|
|
import { useState, useEffect, useRef, useContext } from 'react';
|
|
|
|
import { StoreContext } from 'context/StoreContext';
|
|
|
|
import { CardContext } from 'context/CardContext';
|
|
|
|
import { ChannelContext } from 'context/ChannelContext';
|
|
|
|
import { ProfileContext } from 'context/ProfileContext';
|
2022-10-09 04:55:56 +00:00
|
|
|
import moment from 'moment';
|
2022-09-28 22:09:10 +00:00
|
|
|
|
|
|
|
export function useConversationContext() {
|
|
|
|
const [state, setState] = useState({
|
2022-10-10 06:26:32 +00:00
|
|
|
topic: null,
|
2022-09-28 22:09:10 +00:00
|
|
|
subject: null,
|
|
|
|
logo: null,
|
2022-10-04 21:00:49 +00:00
|
|
|
revision: null,
|
2022-09-28 22:09:10 +00:00
|
|
|
contacts: [],
|
2022-09-30 05:34:31 +00:00
|
|
|
topics: new Map(),
|
2022-10-09 04:55:56 +00:00
|
|
|
createed: null,
|
|
|
|
host: null,
|
2022-09-28 22:09:10 +00:00
|
|
|
});
|
|
|
|
const store = useContext(StoreContext);
|
|
|
|
const card = useContext(CardContext);
|
|
|
|
const channel = useContext(ChannelContext);
|
|
|
|
const profile = useContext(ProfileContext);
|
2022-09-30 05:34:31 +00:00
|
|
|
const topics = useRef(null);
|
2022-09-28 22:09:10 +00:00
|
|
|
const revision = useRef(0);
|
2022-10-06 22:34:29 +00:00
|
|
|
const force = useRef(false);
|
2022-09-29 18:31:55 +00:00
|
|
|
const detailRevision = useRef(0);
|
2022-09-28 22:09:10 +00:00
|
|
|
const syncing = useRef(false);
|
2022-09-29 18:31:55 +00:00
|
|
|
const conversationId = useRef(null);
|
2022-09-30 05:34:31 +00:00
|
|
|
const reset = useRef(false);
|
2022-09-28 22:09:10 +00:00
|
|
|
const setView = useRef(0);
|
|
|
|
|
|
|
|
const updateState = (value) => {
|
|
|
|
setState((s) => ({ ...s, ...value }))
|
|
|
|
}
|
|
|
|
|
2022-09-29 18:31:55 +00:00
|
|
|
const getTopicItems = async (cardId, channelId) => {
|
|
|
|
if (cardId) {
|
|
|
|
return await card.actions.getChannelTopicItems(cardId, channelId);
|
|
|
|
}
|
|
|
|
return await channel.actions.getTopicItems(channelId);
|
|
|
|
}
|
2022-09-30 05:34:31 +00:00
|
|
|
const setTopicItem = async (cardId, channelId, topic) => {
|
2022-09-29 18:31:55 +00:00
|
|
|
if (cardId) {
|
2022-09-30 05:34:31 +00:00
|
|
|
return await card.actions.setChannelTopicItem(cardId, channelId, topic);
|
2022-09-29 18:31:55 +00:00
|
|
|
}
|
2022-09-30 05:34:31 +00:00
|
|
|
return await channel.actions.setTopicItem(channelId, topic);
|
2022-09-29 18:31:55 +00:00
|
|
|
}
|
|
|
|
const clearTopicItem = async (cardId, channelId, topicId) => {
|
|
|
|
if (cardId) {
|
|
|
|
return await card.actions.clearChannelTopicItem(cardId, channelId, topicId);
|
|
|
|
}
|
|
|
|
return await channel.actions.clearTopicItem(channelId, topicId);
|
|
|
|
}
|
|
|
|
const getTopic = async (cardId, channelId, topicId) => {
|
2022-09-29 22:21:18 +00:00
|
|
|
if (cardId) {
|
|
|
|
return await card.actions.getChannelTopic(cardId, channelId, topicId);
|
|
|
|
}
|
|
|
|
return await channel.actions.getTopic(channelId, topicId);
|
2022-09-29 18:31:55 +00:00
|
|
|
}
|
2022-09-29 22:21:18 +00:00
|
|
|
const getTopics = async (cardId, channelId, revision) => {
|
|
|
|
if (cardId) {
|
|
|
|
return await card.actions.getChannelTopics(cardId, channelId, revision);
|
|
|
|
}
|
|
|
|
return await channel.actions.getTopics(channelId, revision)
|
2022-09-29 18:31:55 +00:00
|
|
|
}
|
2022-09-29 22:21:18 +00:00
|
|
|
const getTopicAssetUrl = (cardId, channelId, assetId) => {
|
|
|
|
if (cardId) {
|
|
|
|
return card.actions.getChannelTopicAssetUrl(cardId, channelId, topicId, assetId);
|
|
|
|
}
|
|
|
|
return channel.actions.getTopicAssetUrl(channelId, assetId);
|
2022-09-29 18:31:55 +00:00
|
|
|
}
|
|
|
|
const addTopic = async (cardId, channelId, message, asssets) => {
|
2022-09-29 22:21:18 +00:00
|
|
|
if (cardId) {
|
|
|
|
return await card.actions.addChannelTopic(cardId, channelId, message, assetId);
|
|
|
|
}
|
|
|
|
return await channel.actions.addTopic(channelId, message, assetId);
|
2022-09-29 18:31:55 +00:00
|
|
|
}
|
|
|
|
const setTopicSubject = async (cardId, channelId, topicId, data) => {
|
2022-09-29 22:21:18 +00:00
|
|
|
if (cardId) {
|
|
|
|
return await card.actions.setChannelTopicSubject(cardId, channelId, topicId, data);
|
|
|
|
}
|
|
|
|
return await channel.actions.setTopicSubject(channelId, topicId, data);
|
2022-09-29 18:31:55 +00:00
|
|
|
}
|
2022-09-29 22:21:18 +00:00
|
|
|
const remove = async (cardId, channelId) => {
|
|
|
|
if (cardId) {
|
|
|
|
return await card.actions.removeChannel(cardId, channelId);
|
|
|
|
}
|
|
|
|
return await channel.actions.remove(channelId);
|
2022-09-29 18:31:55 +00:00
|
|
|
}
|
2022-09-29 22:21:18 +00:00
|
|
|
const removeTopic = async (cardId, channelId, topicId) => {
|
|
|
|
if (cardId) {
|
|
|
|
return await card.actions.removeChannelTopic(cardId, channelId, topicId);
|
|
|
|
}
|
|
|
|
return await channel.actions.remvoeTopic(channelId, topicId);
|
2022-09-29 18:31:55 +00:00
|
|
|
}
|
2022-09-30 05:34:31 +00:00
|
|
|
const setSyncRevision = async (cardId, channelId, revision) => {
|
|
|
|
if (cardId) {
|
|
|
|
return await card.actions.setSyncRevision(cardId, channelId, revision);
|
|
|
|
}
|
|
|
|
return await channel.actions.setSyncRevision(channelId, revision);
|
|
|
|
}
|
2022-09-29 18:31:55 +00:00
|
|
|
|
2022-09-28 22:09:10 +00:00
|
|
|
const sync = async () => {
|
|
|
|
const curView = setView.current;
|
2022-09-30 05:34:31 +00:00
|
|
|
if (!syncing.current) {
|
|
|
|
if (reset.current) {
|
|
|
|
revision.current = null;
|
|
|
|
detailRevision.current = null;
|
|
|
|
topics.current = null;
|
|
|
|
reset.current = false;
|
|
|
|
}
|
|
|
|
if (conversationId.current) {
|
|
|
|
const { cardId, channelId } = conversationId.current;
|
|
|
|
const channelItem = getChannel(cardId, channelId);
|
2022-10-06 22:34:29 +00:00
|
|
|
if (channelItem && (channelItem.revision !== revision.current || force.current)) {
|
2022-09-30 05:34:31 +00:00
|
|
|
syncing.current = true;
|
2022-09-29 18:31:55 +00:00
|
|
|
|
2022-09-30 05:34:31 +00:00
|
|
|
try {
|
|
|
|
// set channel details
|
|
|
|
if (detailRevision.current != channelItem.detailRevision) {
|
|
|
|
if (curView === setView.current) {
|
|
|
|
setChannel(channelItem);
|
|
|
|
detailRevision.current = channelItem.detailRevision;
|
|
|
|
}
|
2022-09-29 23:00:48 +00:00
|
|
|
}
|
2022-09-28 22:09:10 +00:00
|
|
|
|
2022-09-30 05:34:31 +00:00
|
|
|
// initial load from store
|
|
|
|
if (!topics.current) {
|
|
|
|
topics.current = new Map();
|
|
|
|
const items = await getTopicItems(cardId, channelId);
|
|
|
|
items.forEach(item => {
|
|
|
|
topics.current.set(item.topicId, item);
|
|
|
|
});
|
2022-09-29 23:00:48 +00:00
|
|
|
}
|
2022-09-30 05:34:31 +00:00
|
|
|
|
|
|
|
// sync from server
|
2022-10-06 22:34:29 +00:00
|
|
|
if (channelItem.topicRevision != channelItem.syncRevision || force.current) {
|
|
|
|
force.current = false;
|
2022-09-30 05:34:31 +00:00
|
|
|
const res = await getTopics(cardId, channelId, channelItem.syncRevision)
|
|
|
|
for (const topic of res.topics) {
|
|
|
|
if (!topic.data) {
|
|
|
|
topics.current.delete(topic.id);
|
|
|
|
await clearTopicItem(cardId, channelId, topic.id);
|
|
|
|
}
|
2022-10-07 05:52:28 +00:00
|
|
|
else {
|
|
|
|
const cached = topics.current.get(topic.id);
|
|
|
|
if (!cached || cached.detailRevision != topic.data.detailRevision) {
|
|
|
|
if (!topic.data.topicDetail) {
|
|
|
|
const updated = await getTopic(cardId, channelId, topic.id);
|
|
|
|
topic.data = updated.data;
|
|
|
|
}
|
|
|
|
if (!topic.data) {
|
|
|
|
topics.current.delete(topic.id);
|
|
|
|
await clearTopicItem(cardId, channelId, topic.id);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
await setTopicItem(cardId, channelId, topic);
|
|
|
|
const { id, revision, data } = topic;
|
|
|
|
topics.current.set(id, { topicId: id, revision: revision, detailRevision: topic.data.detailRevision, detail: topic.data.topicDetail });
|
|
|
|
}
|
2022-09-30 05:34:31 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-10-06 22:34:29 +00:00
|
|
|
await setSyncRevision(cardId, channelId, res.revision);
|
2022-09-29 23:00:48 +00:00
|
|
|
}
|
2022-09-30 05:34:31 +00:00
|
|
|
|
|
|
|
// update revision
|
|
|
|
revision.current = channelItem.revision;
|
|
|
|
if (curView == setView.current) {
|
2022-10-04 21:00:49 +00:00
|
|
|
if (cardId) {
|
|
|
|
card.actions.setChannelReadRevision(cardId, channelId, revision.current);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
channel.actions.setReadRevision(channelId, revision.current);
|
|
|
|
}
|
2022-09-30 05:34:31 +00:00
|
|
|
updateState({ topics: topics.current });
|
2022-09-29 23:00:48 +00:00
|
|
|
}
|
|
|
|
|
2022-09-30 05:34:31 +00:00
|
|
|
syncing.current = false;
|
|
|
|
sync();
|
2022-09-29 18:31:55 +00:00
|
|
|
}
|
2022-09-30 05:34:31 +00:00
|
|
|
catch(err) {
|
|
|
|
console.log(err);
|
|
|
|
syncing.current = false;
|
|
|
|
//TODO set to unsynced state
|
2022-09-29 18:31:55 +00:00
|
|
|
}
|
|
|
|
}
|
2022-09-28 22:09:10 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const getCard = (guid) => {
|
|
|
|
let contact = null
|
|
|
|
card.state.cards.forEach((card, cardId, map) => {
|
|
|
|
if (card?.profile?.guid === guid) {
|
|
|
|
contact = card;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
return contact;
|
|
|
|
}
|
|
|
|
|
|
|
|
const getChannel = (cardId, channelId) => {
|
|
|
|
if (cardId) {
|
|
|
|
const entry = card.state.cards.get(cardId);
|
|
|
|
return entry?.channels.get(channelId);
|
|
|
|
}
|
|
|
|
return channel.state.channels.get(channelId);
|
|
|
|
}
|
|
|
|
|
|
|
|
const setChannel = (item) => {
|
|
|
|
let contacts = [];
|
|
|
|
let logo = null;
|
2022-10-10 06:26:32 +00:00
|
|
|
let topic = null;
|
2022-09-28 22:09:10 +00:00
|
|
|
let subject = null;
|
|
|
|
|
2022-10-09 04:55:56 +00:00
|
|
|
let timestamp;
|
|
|
|
const date = new Date(item.detail.created * 1000);
|
|
|
|
const now = new Date();
|
|
|
|
const offset = now.getTime() - date.getTime();
|
|
|
|
if(offset < 86400000) {
|
|
|
|
timestamp = moment(date).format('h:mma');
|
|
|
|
}
|
|
|
|
else if (offset < 31449600000) {
|
|
|
|
timestamp = moment(date).format('M/DD');
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
timestamp = moment(date).format('M/DD/YYYY');
|
|
|
|
}
|
|
|
|
|
2022-09-28 22:09:10 +00:00
|
|
|
if (!item) {
|
2022-10-10 06:26:32 +00:00
|
|
|
updateState({ contacts, logo, subject, topic });
|
2022-09-28 22:09:10 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (item.cardId) {
|
|
|
|
contacts.push(card.state.cards.get(item.cardId));
|
|
|
|
}
|
|
|
|
if (item?.detail?.members) {
|
|
|
|
const profileGuid = profile.state.profile.guid;
|
|
|
|
item.detail.members.forEach(guid => {
|
|
|
|
if (profileGuid !== guid) {
|
|
|
|
const contact = getCard(guid);
|
|
|
|
contacts.push(contact);
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
if (contacts.length === 0) {
|
|
|
|
logo = 'solution';
|
|
|
|
}
|
|
|
|
else if (contacts.length === 1) {
|
|
|
|
if (contacts[0]?.profile?.imageSet) {
|
|
|
|
logo = card.actions.getCardLogo(contacts[0].cardId, contacts[0].profileRevision);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
logo = 'avatar';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
logo = 'appstore';
|
|
|
|
}
|
|
|
|
|
|
|
|
if (item?.detail?.data) {
|
|
|
|
try {
|
2022-10-10 06:26:32 +00:00
|
|
|
topic = JSON.parse(item?.detail?.data).subject;
|
|
|
|
subject = topic;
|
2022-09-28 22:09:10 +00:00
|
|
|
}
|
|
|
|
catch (err) {
|
|
|
|
console.log(err);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!subject) {
|
|
|
|
if (contacts.length) {
|
|
|
|
let names = [];
|
|
|
|
for (let contact of contacts) {
|
|
|
|
if (contact?.profile?.name) {
|
|
|
|
names.push(contact.profile.name);
|
|
|
|
}
|
|
|
|
else if (contact?.profile?.handle) {
|
|
|
|
names.push(contact?.profile?.handle);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
subject = names.join(', ');
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
subject = "Notes";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-10-10 06:26:32 +00:00
|
|
|
updateState({ topic, subject, logo, contacts, host: item.cardId, created: timestamp });
|
2022-09-28 22:09:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
sync();
|
|
|
|
}, [card, channel]);
|
|
|
|
|
|
|
|
const actions = {
|
2022-10-04 18:52:22 +00:00
|
|
|
setChannel: (selected) => {
|
|
|
|
if (selected == null) {
|
2022-09-29 18:31:55 +00:00
|
|
|
setView.current++;
|
|
|
|
conversationId.current = null;
|
2022-09-30 05:34:31 +00:00
|
|
|
reset.current = true;
|
|
|
|
updateState({ subject: null, logo: null, contacts: [], topics: new Map() });
|
2022-09-29 18:31:55 +00:00
|
|
|
}
|
2022-10-04 18:52:22 +00:00
|
|
|
else if (selected.cardId !== conversationId.current?.cardId || selected.channelId !== conversationId.current?.channelId) {
|
2022-09-28 22:09:10 +00:00
|
|
|
setView.current++;
|
2022-10-04 18:52:22 +00:00
|
|
|
conversationId.current = selected;
|
2022-09-30 05:34:31 +00:00
|
|
|
reset.current = true;
|
|
|
|
updateState({ subject: null, logo: null, contacts: [], topics: new Map() });
|
2022-09-28 22:09:10 +00:00
|
|
|
sync();
|
2022-10-04 18:52:22 +00:00
|
|
|
const { cardId, channelId, revision } = selected;
|
|
|
|
if (cardId) {
|
|
|
|
card.actions.setChannelReadRevision(cardId, channelId, revision);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
channel.actions.setReadRevision(channelId, revision);
|
|
|
|
}
|
2022-09-28 22:09:10 +00:00
|
|
|
}
|
|
|
|
},
|
2022-10-05 07:09:57 +00:00
|
|
|
getTopicAssetUrl: (topicId, assetId) => {
|
|
|
|
if (conversationId.current) {
|
|
|
|
const { cardId, channelId } = conversationId.current;
|
|
|
|
if (cardId) {
|
|
|
|
return card.actions.getChannelTopicAssetUrl(cardId, channelId, topicId, assetId);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return channel.actions.getTopicAssetUrl(channelId, topicId, assetId);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return null;
|
|
|
|
},
|
2022-10-06 22:34:29 +00:00
|
|
|
addTopic: async (message, files) => {
|
|
|
|
if (conversationId.current) {
|
|
|
|
const { cardId, channelId } = conversationId.current;
|
|
|
|
if (cardId) {
|
|
|
|
await card.actions.addChannelTopic(cardId, channelId, message, files);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
await channel.actions.addTopic(channelId, message, files);
|
|
|
|
}
|
|
|
|
force.current = true;
|
|
|
|
sync();
|
|
|
|
}
|
|
|
|
},
|
2022-10-10 06:26:32 +00:00
|
|
|
setSubject: async (subject) => {
|
|
|
|
if (conversationId.current) {
|
|
|
|
const { cardId, channelId } = conversationId.current;
|
|
|
|
if (cardId) {
|
|
|
|
throw new Error("can only set hosted channel subjects");
|
|
|
|
}
|
|
|
|
await channel.actions.setSubject(channelId, subject);
|
|
|
|
}
|
|
|
|
},
|
2022-10-10 06:55:08 +00:00
|
|
|
remove: async () => {
|
|
|
|
if (conversationId.current) {
|
|
|
|
const { cardId, channelId } = conversationId.current;
|
|
|
|
await remove(cardId, channelId);
|
|
|
|
}
|
|
|
|
},
|
2022-10-18 06:22:06 +00:00
|
|
|
removeTopic: async (topicId) => {
|
|
|
|
if (conversationId.current) {
|
|
|
|
const { cardId, channelId } = conversationId.current;
|
|
|
|
if (cardId) {
|
|
|
|
await card.actions.removeChannelTopic(cardId, channelId, topicId);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
await channel.actions.removeTopic(channelId, topicId);
|
|
|
|
}
|
|
|
|
force.current = true;
|
|
|
|
sync();
|
|
|
|
}
|
|
|
|
},
|
2022-10-18 18:13:45 +00:00
|
|
|
setTopicSubject: async (topicId, data) => {
|
|
|
|
if (conversationId.current) {
|
|
|
|
const { cardId, channelId } = conversationId.current;
|
|
|
|
if (cardId) {
|
|
|
|
return await card.actions.setChannelTopicSubject(cardId, channelId, topicId, data);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return await channel.actions.setTopicSubject(channelId, topicId, data);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
force.current = true;
|
|
|
|
sync();
|
|
|
|
},
|
2022-10-11 05:05:15 +00:00
|
|
|
setCard: async (id) => {
|
|
|
|
if (conversationId.current) {
|
|
|
|
const { cardId, channelId } = conversationId.current;
|
|
|
|
if (cardId) {
|
|
|
|
throw new Error("can only set members on hosted channel");
|
|
|
|
}
|
|
|
|
await channel.actions.setCard(channelId, id);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
clearCard: async (id) => {
|
|
|
|
if (conversationId.current) {
|
|
|
|
const { cardId, channelId } = conversationId.current;
|
|
|
|
if (cardId) {
|
|
|
|
throw new Error("can only clear members on hosted channel");
|
|
|
|
}
|
|
|
|
await channel.actions.clearCard(channelId, id);
|
|
|
|
}
|
|
|
|
},
|
2022-10-11 19:18:08 +00:00
|
|
|
setBlocked: async () => {
|
|
|
|
if (conversationId.current) {
|
|
|
|
const { cardId, channelId } = conversationId.current;
|
|
|
|
if (cardId) {
|
|
|
|
await card.actions.setChannelBlocked(cardId, channelId);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
await channel.actions.setBlocked(channelId);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
2022-09-28 22:09:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return { state, actions }
|
|
|
|
}
|
|
|
|
|
|
|
|
|