2020-12-28 18:41:38 +01:00
|
|
|
import log from "@converse/headless/log";
|
2020-12-28 21:04:44 +01:00
|
|
|
import tpl_pending_contact from "./templates/pending_contact.js";
|
|
|
|
import tpl_requesting_contact from "./templates/requesting_contact.js";
|
|
|
|
import tpl_roster_item from "./templates/roster_item.js";
|
2021-01-26 14:01:37 +01:00
|
|
|
import { CustomElement } from 'components/element.js';
|
2020-12-28 18:41:38 +01:00
|
|
|
import { __ } from 'i18n';
|
|
|
|
import { _converse, api, converse } from "@converse/headless/core";
|
|
|
|
|
|
|
|
const u = converse.env.utils;
|
|
|
|
|
|
|
|
|
2021-01-26 14:01:37 +01:00
|
|
|
class RosterContact extends CustomElement {
|
|
|
|
|
|
|
|
static get properties () {
|
|
|
|
return {
|
|
|
|
model: { type: Object }
|
2020-12-28 18:41:38 +01:00
|
|
|
}
|
2021-01-26 14:01:37 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
connectedCallback () {
|
|
|
|
super.connectedCallback();
|
|
|
|
this.listenTo(this.model, "change", this.requestUpdate);
|
|
|
|
this.listenTo(this.model, "highlight", this.requestUpdate);
|
|
|
|
this.listenTo(this.model, 'vcard:change', this.requestUpdate);
|
|
|
|
}
|
|
|
|
|
|
|
|
render () {
|
|
|
|
const ask = this.model.get('ask');
|
|
|
|
const requesting = this.model.get('requesting');
|
|
|
|
const subscription = this.model.get('subscription');
|
|
|
|
const jid = this.model.get('jid');
|
2020-12-28 18:41:38 +01:00
|
|
|
|
|
|
|
if ((ask === 'subscribe') || (subscription === 'from')) {
|
|
|
|
/* ask === 'subscribe'
|
|
|
|
* Means we have asked to subscribe to them.
|
|
|
|
*
|
|
|
|
* subscription === 'from'
|
|
|
|
* They are subscribed to use, but not vice versa.
|
|
|
|
* We assume that there is a pending subscription
|
|
|
|
* from us to them (otherwise we're in a state not
|
|
|
|
* supported by converse.js).
|
|
|
|
*
|
|
|
|
* So in both cases the user is a "pending" contact.
|
|
|
|
*/
|
|
|
|
const display_name = this.model.getDisplayName();
|
2021-01-26 14:01:37 +01:00
|
|
|
return tpl_pending_contact(Object.assign(
|
|
|
|
this.model.toJSON(), {
|
|
|
|
display_name,
|
|
|
|
'openChat': ev => this.openChat(ev),
|
|
|
|
'removeContact': ev => this.removeContact(ev)
|
|
|
|
}));
|
2020-12-28 21:04:44 +01:00
|
|
|
|
2020-12-28 18:41:38 +01:00
|
|
|
} else if (requesting === true) {
|
|
|
|
const display_name = this.model.getDisplayName();
|
2021-01-26 14:01:37 +01:00
|
|
|
return tpl_requesting_contact(
|
2020-12-28 18:41:38 +01:00
|
|
|
Object.assign(this.model.toJSON(), {
|
|
|
|
display_name,
|
2021-01-26 14:01:37 +01:00
|
|
|
'openChat': ev => this.openChat(ev),
|
|
|
|
'acceptRequest': ev => this.acceptRequest(ev),
|
|
|
|
'declineRequest': ev => this.declineRequest(ev),
|
2020-12-28 18:41:38 +01:00
|
|
|
'desc_accept': __("Click to accept the contact request from %1$s", display_name),
|
|
|
|
'desc_decline': __("Click to decline the contact request from %1$s", display_name),
|
|
|
|
'allow_chat_pending_contacts': api.settings.get('allow_chat_pending_contacts')
|
|
|
|
})
|
2021-01-26 14:01:37 +01:00
|
|
|
);
|
|
|
|
} else if (subscription === 'both' || subscription === 'to' || u.isSameBareJID(jid, _converse.connection.jid)) {
|
|
|
|
return this.renderRosterItem(this.model);
|
2020-12-28 18:41:38 +01:00
|
|
|
}
|
2021-01-26 14:01:37 +01:00
|
|
|
}
|
|
|
|
|
2021-02-06 12:29:56 +01:00
|
|
|
renderRosterItem (item) {
|
2021-01-26 14:01:37 +01:00
|
|
|
const STATUSES = {
|
|
|
|
'dnd': __('This contact is busy'),
|
|
|
|
'online': __('This contact is online'),
|
|
|
|
'offline': __('This contact is offline'),
|
|
|
|
'unavailable': __('This contact is unavailable'),
|
|
|
|
'xa': __('This contact is away for an extended period'),
|
|
|
|
'away': __('This contact is away')
|
|
|
|
};
|
2020-12-28 18:41:38 +01:00
|
|
|
|
|
|
|
const show = item.presence.get('show') || 'offline';
|
|
|
|
let status_icon;
|
|
|
|
if (show === 'online') {
|
|
|
|
status_icon = 'fa fa-circle chat-status chat-status--online';
|
|
|
|
} else if (show === 'away') {
|
|
|
|
status_icon = 'fa fa-circle chat-status chat-status--away';
|
|
|
|
} else if (show === 'xa') {
|
|
|
|
status_icon = 'far fa-circle chat-status chat-status-xa';
|
|
|
|
} else if (show === 'dnd') {
|
|
|
|
status_icon = 'fa fa-minus-circle chat-status chat-status--busy';
|
|
|
|
} else {
|
|
|
|
status_icon = 'fa fa-times-circle chat-status chat-status--offline';
|
|
|
|
}
|
|
|
|
const display_name = item.getDisplayName();
|
2021-01-26 14:01:37 +01:00
|
|
|
return tpl_roster_item(
|
2020-12-28 18:41:38 +01:00
|
|
|
Object.assign(item.toJSON(), {
|
|
|
|
show,
|
|
|
|
display_name,
|
|
|
|
status_icon,
|
2021-01-26 14:01:37 +01:00
|
|
|
'openChat': ev => this.openChat(ev),
|
|
|
|
'removeContact': ev => this.removeContact(ev),
|
|
|
|
'getAvatarData': () => this.getAvatarData(),
|
2020-12-28 18:41:38 +01:00
|
|
|
'desc_status': STATUSES[show],
|
2021-02-06 12:29:56 +01:00
|
|
|
'num_unread': item.get('num_unread') || 0
|
2020-12-28 18:41:38 +01:00
|
|
|
})
|
2021-01-26 14:01:37 +01:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
getAvatarData () {
|
|
|
|
const image_type = this.model.vcard?.get('image_type') || _converse.DEFAULT_IMAGE_TYPE;
|
|
|
|
const image_data = this.model.vcard?.get('image') || _converse.DEFAULT_IMAGE;
|
|
|
|
const image = "data:" + image_type + ";base64," + image_data;
|
|
|
|
return {
|
|
|
|
'classes': 'avatar',
|
|
|
|
'height': 30,
|
|
|
|
'width': 30,
|
|
|
|
image,
|
|
|
|
};
|
|
|
|
}
|
2020-12-28 18:41:38 +01:00
|
|
|
|
|
|
|
openChat (ev) {
|
2021-01-26 14:01:37 +01:00
|
|
|
ev?.preventDefault?.();
|
2020-12-28 18:41:38 +01:00
|
|
|
this.model.openChat();
|
2021-01-26 14:01:37 +01:00
|
|
|
}
|
2020-12-28 18:41:38 +01:00
|
|
|
|
2021-01-26 14:01:37 +01:00
|
|
|
removeContact (ev) {
|
|
|
|
ev?.preventDefault?.();
|
2020-12-28 18:41:38 +01:00
|
|
|
if (!api.settings.get('allow_contact_removal')) { return; }
|
|
|
|
if (!confirm(__("Are you sure you want to remove this contact?"))) { return; }
|
|
|
|
|
|
|
|
try {
|
2021-01-26 14:01:37 +01:00
|
|
|
this.model.removeFromRoster();
|
2020-12-28 18:41:38 +01:00
|
|
|
if (this.model.collection) {
|
|
|
|
// The model might have already been removed as
|
|
|
|
// result of a roster push.
|
|
|
|
this.model.destroy();
|
|
|
|
}
|
|
|
|
} catch (e) {
|
|
|
|
log.error(e);
|
|
|
|
api.alert('error', __('Error'),
|
|
|
|
[__('Sorry, there was an error while trying to remove %1$s as a contact.', this.model.getDisplayName())]
|
|
|
|
);
|
|
|
|
}
|
2021-01-26 14:01:37 +01:00
|
|
|
}
|
2020-12-28 18:41:38 +01:00
|
|
|
|
|
|
|
async acceptRequest (ev) {
|
2021-01-26 14:01:37 +01:00
|
|
|
ev?.preventDefault?.();
|
2020-12-28 18:41:38 +01:00
|
|
|
|
|
|
|
await _converse.roster.sendContactAddIQ(
|
|
|
|
this.model.get('jid'),
|
|
|
|
this.model.getFullname(),
|
|
|
|
[]
|
|
|
|
);
|
|
|
|
this.model.authorize().subscribe();
|
2021-01-26 14:01:37 +01:00
|
|
|
}
|
2020-12-28 18:41:38 +01:00
|
|
|
|
|
|
|
declineRequest (ev) {
|
|
|
|
if (ev && ev.preventDefault) { ev.preventDefault(); }
|
|
|
|
const result = confirm(__("Are you sure you want to decline this contact request?"));
|
|
|
|
if (result === true) {
|
|
|
|
this.model.unauthorize().destroy();
|
|
|
|
}
|
|
|
|
return this;
|
|
|
|
}
|
2021-01-26 14:01:37 +01:00
|
|
|
}
|
2020-12-28 18:41:38 +01:00
|
|
|
|
2021-01-26 14:01:37 +01:00
|
|
|
api.elements.define('converse-roster-contact', RosterContact);
|