diff --git a/core/language/us.json b/core/language/us.json index 2498cc47..c59951b0 100644 --- a/core/language/us.json +++ b/core/language/us.json @@ -837,7 +837,8 @@ "cchange93": "Image copied to clipboard", "cchange94": "loaded", "cchange95": "Only my resources", - "cchange96": "Open Group Management" + "cchange96": "Open Group Management", + "cchange97": "Join group link copied to clipboard" }, "welcomepage": { "wcchange1": "Welcome to Q-Chat", @@ -1172,6 +1173,7 @@ }, "notifications": { "notify1": "Confirming transaction", - "notify2": "Transaction confirmed" + "notify2": "Transaction confirmed", + "explanation": "Your transaction is getting confirmed. To track its progress, click on the bell icon." } } \ No newline at end of file diff --git a/core/src/components/login-view/login-view.js b/core/src/components/login-view/login-view.js index c6ef8a5b..bc044daa 100644 --- a/core/src/components/login-view/login-view.js +++ b/core/src/components/login-view/login-view.js @@ -15,7 +15,7 @@ import './login-section.js' import '../qort-theme-toggle.js' import settings from '../../functional-components/settings-page.js' -import { addAutoLoadImageChat, removeAutoLoadImageChat, addChatLastSeen, allowQAPPAutoAuth, removeQAPPAutoAuth, removeQAPPAutoLists, allowQAPPAutoLists, addTabInfo, setTabNotifications, setNewTab, setNewNotification } from '../../redux/app/app-actions.js' +import { addAutoLoadImageChat, removeAutoLoadImageChat, addChatLastSeen, allowQAPPAutoAuth, removeQAPPAutoAuth, removeQAPPAutoLists, allowQAPPAutoLists, addTabInfo, setTabNotifications, setNewTab, setNewNotification, setSideEffectAction } from '../../redux/app/app-actions.js' window.reduxStore = store window.reduxAction = { @@ -29,7 +29,8 @@ window.reduxAction = { addTabInfo: addTabInfo, setTabNotifications: setTabNotifications, setNewTab: setNewTab, - setNewNotification: setNewNotification + setNewNotification: setNewNotification, + setSideEffectAction: setSideEffectAction } const animationDuration = 0.7 // Seconds diff --git a/core/src/components/notification-view/notification-bell-general.js b/core/src/components/notification-view/notification-bell-general.js index 804c63b2..125c8095 100644 --- a/core/src/components/notification-view/notification-bell-general.js +++ b/core/src/components/notification-view/notification-bell-general.js @@ -9,24 +9,16 @@ import { store } from '../../store.js'; import { setNewNotification, setNewTab } from '../../redux/app/app-actions.js'; import { routes } from '../../plugins/routes.js'; import '@material/mwc-icon'; -import { translate } from 'lit-translate'; +import { translate, get } from 'lit-translate'; import { repeat } from 'lit/directives/repeat.js'; import config from '../../notifications/config.js'; import '../../../../plugins/plugins/core/components/TimeAgo.js'; import './popover.js'; -const currentNotification = { - type: 'JOIN_GROUP', - timestamp: Date.now(), - status: 'confirming', - reference: { - signature: - '5wpPP7ngE13z8x7FKr3tkx5AhMyzWAcFeTmkyefSbddRZ3ieMRcbwt4VDz5bakJzpFaE16NcSofa8w35AGLN4J47', - }, -}; -const notifications = [currentNotification]; + + class NotificationBellGeneral extends connect(store)(LitElement) { static properties = { notifications: { type: Array }, @@ -111,7 +103,7 @@ class NotificationBellGeneral extends connect(store)(LitElement) {
{ return myPlug === undefined ? 'about:blank' : `${window.location.origin}/plugin/${myPlug.domain}/${myPlug.page}${this.linkParam}` } @@ -460,6 +461,8 @@ class ShowPlugin extends connect(store)(LitElement) { id: this.uid.rnd() }) this.currentTab = lengthOfTabs + this.tabs = [...this.tabs] + this.requestUpdate() }} >+
@@ -845,6 +848,7 @@ class ShowPlugin extends connect(store)(LitElement) { store.dispatch(setNewTab(null)) //clear newTab } + this.requestUpdate() } if(state.app.isOpenDevDialog){ diff --git a/core/src/plugins/streams.js b/core/src/plugins/streams.js index 8aee79d3..bc4bae3a 100644 --- a/core/src/plugins/streams.js +++ b/core/src/plugins/streams.js @@ -8,6 +8,7 @@ const APP_INFO_STATE = 'app_info_state' const CHAT_HEADS_STREAM_NAME = 'chat_heads' const NODE_CONFIG_STREAM_NAME = 'node_config' const CHAT_LAST_SEEN = 'chat_last_seen' +const SIDE_EFFECT_ACTION = 'side_effect_action' export const loggedInStream = new EpmlStream(LOGIN_STREAM_NAME, () => store.getState().app.loggedIn) export const configStream = new EpmlStream(CONFIG_STREAM_NAME, () => store.getState().config) @@ -16,6 +17,8 @@ export const appInfoStateStream = new EpmlStream(APP_INFO_STATE, () => store.get export const chatHeadsStateStream = new EpmlStream(CHAT_HEADS_STREAM_NAME, () => store.getState().app.chatHeads) export const nodeConfigStream = new EpmlStream(NODE_CONFIG_STREAM_NAME, () => store.getState().app.nodeConfig) export const chatLastSeenStream = new EpmlStream(CHAT_LAST_SEEN, () => store.getState().app.chatLastSeen) +export const sideEffectActionStream = new EpmlStream(SIDE_EFFECT_ACTION, () => store.getState().app.sideEffectAction) + let oldState = { @@ -56,6 +59,10 @@ store.subscribe(() => { if (oldState.app.appInfo !== state.app.appInfo) { appInfoStateStream.emit(state.app.appInfo) } + if (oldState.app.sideEffectAction !== state.app.sideEffectAction) { + sideEffectActionStream.emit(state.app.sideEffectAction) + } + oldState = state }) diff --git a/core/src/redux/app/actions/app-core.js b/core/src/redux/app/actions/app-core.js index 0b5f59dd..fa2e8380 100644 --- a/core/src/redux/app/actions/app-core.js +++ b/core/src/redux/app/actions/app-core.js @@ -1,5 +1,5 @@ // Core App Actions here... -import { UPDATE_BLOCK_INFO, UPDATE_NODE_STATUS, UPDATE_NODE_INFO, CHAT_HEADS, ACCOUNT_INFO, ADD_AUTO_LOAD_IMAGES_CHAT, REMOVE_AUTO_LOAD_IMAGES_CHAT, ALLOW_QAPP_AUTO_AUTH, REMOVE_QAPP_AUTO_AUTH, SET_CHAT_LAST_SEEN, ADD_CHAT_LAST_SEEN, ALLOW_QAPP_AUTO_LISTS, REMOVE_QAPP_AUTO_LISTS, SET_NEW_TAB, ADD_TAB_INFO, SET_TAB_NOTIFICATIONS, IS_OPEN_DEV_DIALOG, SET_NEW_NOTIFICATION } from '../app-action-types.js' +import { UPDATE_BLOCK_INFO, UPDATE_NODE_STATUS, UPDATE_NODE_INFO, CHAT_HEADS, ACCOUNT_INFO, ADD_AUTO_LOAD_IMAGES_CHAT, REMOVE_AUTO_LOAD_IMAGES_CHAT, ALLOW_QAPP_AUTO_AUTH, REMOVE_QAPP_AUTO_AUTH, SET_CHAT_LAST_SEEN, ADD_CHAT_LAST_SEEN, ALLOW_QAPP_AUTO_LISTS, REMOVE_QAPP_AUTO_LISTS, SET_NEW_TAB, ADD_TAB_INFO, SET_TAB_NOTIFICATIONS, IS_OPEN_DEV_DIALOG, SET_NEW_NOTIFICATION, SET_SIDE_EFFECT } from '../app-action-types.js' export const doUpdateBlockInfo = (blockObj) => { return (dispatch, getState) => { @@ -150,4 +150,11 @@ export const setTabNotifications = (payload) => { type: SET_TAB_NOTIFICATIONS, payload } +} + +export const setSideEffectAction = (payload)=> { + return { + type: SET_SIDE_EFFECT, + payload + } } \ No newline at end of file diff --git a/core/src/redux/app/app-action-types.js b/core/src/redux/app/app-action-types.js index eb12f9fa..fd5e06f7 100644 --- a/core/src/redux/app/app-action-types.js +++ b/core/src/redux/app/app-action-types.js @@ -32,3 +32,4 @@ export const ADD_TAB_INFO = 'ADD_TAB_INFO' export const SET_TAB_NOTIFICATIONS = 'SET_TAB_NOTIFICATIONS' export const IS_OPEN_DEV_DIALOG = 'IS_OPEN_DEV_DIALOG' export const SET_NEW_NOTIFICATION = 'SET_NEW_NOTIFICATION' +export const SET_SIDE_EFFECT= 'SET_SIDE_EFFECT' diff --git a/core/src/redux/app/app-reducer.js b/core/src/redux/app/app-reducer.js index 63a062f0..43f2dc27 100644 --- a/core/src/redux/app/app-reducer.js +++ b/core/src/redux/app/app-reducer.js @@ -1,6 +1,6 @@ // Loading state, login state, isNavDrawOpen state etc. None of this needs to be saved to localstorage. import { loadStateFromLocalStorage, saveStateToLocalStorage } from '../../localStorageHelpers.js' -import { LOG_IN, LOG_OUT, NETWORK_CONNECTION_STATUS, INIT_WORKERS, ADD_PLUGIN_URL, ADD_PLUGIN, ADD_NEW_PLUGIN_URL, NAVIGATE, SELECT_ADDRESS, ACCOUNT_INFO, CHAT_HEADS, UPDATE_BLOCK_INFO, UPDATE_NODE_STATUS, UPDATE_NODE_INFO, LOAD_NODE_CONFIG, SET_NODE, ADD_NODE, PAGE_URL, ADD_AUTO_LOAD_IMAGES_CHAT, REMOVE_AUTO_LOAD_IMAGES_CHAT, ALLOW_QAPP_AUTO_AUTH, REMOVE_QAPP_AUTO_AUTH, SET_CHAT_LAST_SEEN, ADD_CHAT_LAST_SEEN, ALLOW_QAPP_AUTO_LISTS, REMOVE_QAPP_AUTO_LISTS, SET_NEW_TAB, ADD_TAB_INFO, SET_TAB_NOTIFICATIONS, IS_OPEN_DEV_DIALOG, REMOVE_NODE, EDIT_NODE, SET_NEW_NOTIFICATION } from './app-action-types.js' +import { LOG_IN, LOG_OUT, NETWORK_CONNECTION_STATUS, INIT_WORKERS, ADD_PLUGIN_URL, ADD_PLUGIN, ADD_NEW_PLUGIN_URL, NAVIGATE, SELECT_ADDRESS, ACCOUNT_INFO, CHAT_HEADS, UPDATE_BLOCK_INFO, UPDATE_NODE_STATUS, UPDATE_NODE_INFO, LOAD_NODE_CONFIG, SET_NODE, ADD_NODE, PAGE_URL, ADD_AUTO_LOAD_IMAGES_CHAT, REMOVE_AUTO_LOAD_IMAGES_CHAT, ALLOW_QAPP_AUTO_AUTH, REMOVE_QAPP_AUTO_AUTH, SET_CHAT_LAST_SEEN, ADD_CHAT_LAST_SEEN, ALLOW_QAPP_AUTO_LISTS, REMOVE_QAPP_AUTO_LISTS, SET_NEW_TAB, ADD_TAB_INFO, SET_TAB_NOTIFICATIONS, IS_OPEN_DEV_DIALOG, REMOVE_NODE, EDIT_NODE, SET_NEW_NOTIFICATION, SET_SIDE_EFFECT } from './app-action-types.js' import { initWorkersReducer } from './reducers/init-workers.js' import { loginReducer } from './reducers/login-reducer.js' import { setNode, addNode, removeNode, editNode } from './reducers/manage-node.js' @@ -51,7 +51,8 @@ const INITIAL_STATE = { newTab: null, tabInfo: {}, isOpenDevDialog: false, - newNotification: null + newNotification: null, + sideEffectAction: null } export default (state = INITIAL_STATE, action) => { @@ -284,6 +285,12 @@ export default (state = INITIAL_STATE, action) => { newNotification: action.payload } } + case SET_SIDE_EFFECT: { + return { + ...state, + sideEffectAction: action.payload + } + } default: return state diff --git a/plugins/plugins/core/components/ChatPage.js b/plugins/plugins/core/components/ChatPage.js index 351e5a1f..b9a5ceb0 100644 --- a/plugins/plugins/core/components/ChatPage.js +++ b/plugins/plugins/core/components/ChatPage.js @@ -368,6 +368,19 @@ class ChatPage extends LitElement { console.log } } + + async copyJoinGroupLinkToClipboard() { + try { + const link = `qortal://use-group/action-join/groupid-${this.groupInfo.groupId}` + let copyString1 = get('chatpage.cchange97'); + await navigator.clipboard.writeText(link); + parentEpml.request('showSnackBar', `${copyString1}`); + } catch (err) { + let copyString2 = get('walletpage.wchange39'); + parentEpml.request('showSnackBar', `${copyString2}`); + console.error('Copy to clipboard error:', err); + } + } render() { @@ -390,6 +403,11 @@ class ChatPage extends LitElement {
+ ${(!this.isReceipient && +this._chatId !== 0 && this.groupInfo.isOpen) ? + html` + link + ` + : ''} photo_library ${(!this.isReceipient && +this._chatId !== 0) ? html` diff --git a/plugins/plugins/core/components/ChatScroller.js b/plugins/plugins/core/components/ChatScroller.js index 48faa283..9da8a1b2 100644 --- a/plugins/plugins/core/components/ChatScroller.js +++ b/plugins/plugins/core/components/ChatScroller.js @@ -53,7 +53,21 @@ const extractComponents = async (url) => { } url = url.replace(/^(qortal:\/\/)/, ''); - if (url.includes('/')) { + if (url.startsWith('use-')) { + // Handle the new 'use' format + let parts = url.split('/'); + const type = parts[0].split('-')[1]; // e.g., 'group' from 'use-group' + parts.shift(); + const action = parts.length > 0 ? parts[0].split('-')[1] : null; // e.g., 'invite' from 'action-invite' + parts.shift(); + const idPrefix = parts.length > 0 ? parts[0].split('-')[0] : null; // e.g., 'groupid' from 'groupid-321' + const id = parts.length > 0 ? parts[0].split('-')[1] : null; // e.g., '321' from 'groupid-321' + return { + type: type, + action: action, + [idPrefix]: id + } + } else if (url.includes('/')) { let parts = url.split('/'); const service = parts[0].toUpperCase(); parts.shift(); @@ -114,6 +128,33 @@ function processText(input) { try { const res = await extractComponents(part); if (!res) return; + if(res.type && res.groupid && res.action === 'join'){ + window.parent.reduxStore.dispatch( + window.parent.reduxAction.setNewTab({ + url: `group-management`, + id: uid.rnd(), + myPlugObj: { + "url": "group-management", + "domain": "core", + "page": "group-management/index.html", + "title": "Group Management", + "icon": "vaadin:group", + "mwcicon": "group", + "pluginNumber": "plugin-fJZNpyLGTl", + "menus": [], + "parent": false + }, + openExisting: true + }) + ); + window.parent.reduxStore.dispatch( + window.parent.reduxAction.setSideEffectAction({ + type: 'openJoinGroupModal', + data: +res.groupid + }) + ); + return + } const { service, name, identifier, path } = res; let query = `?service=${service}`; if (name) { diff --git a/plugins/plugins/core/group-management/group-management.src.js b/plugins/plugins/core/group-management/group-management.src.js index 56e4e7b7..3503aaa8 100644 --- a/plugins/plugins/core/group-management/group-management.src.js +++ b/plugins/plugins/core/group-management/group-management.src.js @@ -1743,6 +1743,12 @@ class GroupManagement extends LitElement { }) return joinedG } + const getGroupInfo = async (groupId) => { + let joinedG = await parentEpml.request('apiCall', { + url: `/groups/${groupId}` + }) + return joinedG + } const getGroupInvites = async () => { const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node] @@ -1839,6 +1845,25 @@ class GroupManagement extends LitElement { if (!selectedAddress || Object.entries(selectedAddress).length === 0) return this.selectedAddress = selectedAddress }) + parentEpml.subscribe('side_effect_action', async sideEffectActionParam => { + const sideEffectAction = JSON.parse(sideEffectActionParam) + + if(sideEffectAction && sideEffectAction.type === 'openJoinGroupModal'){ + const res = await getGroupInfo(sideEffectAction.data) + if(res && res.groupId){ + if(res.isOpen){ + this.joinGroup(res) + + } else { + let snackbarstring = get("managegroup.mg45") + parentEpml.request('showSnackBar', `${snackbarstring}`) + } + } + window.parent.reduxStore.dispatch( + window.parent.reduxAction.setSideEffectAction(null) + ); + } + }) parentEpml.subscribe('config', c => { if (!configLoaded) { setTimeout(getOpen_JoinedGroups, 1) diff --git a/plugins/plugins/core/messaging/q-chat/q-chat.src.js b/plugins/plugins/core/messaging/q-chat/q-chat.src.js index f8bcf947..f73558c4 100644 --- a/plugins/plugins/core/messaging/q-chat/q-chat.src.js +++ b/plugins/plugins/core/messaging/q-chat/q-chat.src.js @@ -727,7 +727,7 @@ class Chat extends LitElement { } renderLoadingText() { - return html`${translate("chatpage.cchange2")}` + return html`
` } renderSendText() {