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() {