/**
* Sync page — device linking via autopass; create invite, pair with invite, show status.
* Depends: core/utils.js ($), ui/modal.js (openModal, closeModal, showModalError), ui/toast.js (showToast)
*/
/**
* Update the sync status UI from the native host.
*/
function updateSyncStatus() {
chrome.runtime.sendMessage(
{ target: 'holesail-native', action: 'send', payload: { type: 'getSyncStatus' } },
(response) => {
if (chrome.runtime.lastError) return;
const dot = $('syncStatusDot');
const text = $('syncStatusText');
const lastSynced = $('syncLastSynced');
const btnCopy = $('btnCopyInvite');
const inviteDisplay = $('syncInviteDisplay');
if (!text) return;
if (!response || response.error) {
if (dot) dot.style.background = 'var(--text4)';
text.textContent = 'Not linked';
if (lastSynced) lastSynced.textContent = '';
if (btnCopy) btnCopy.style.display = 'none';
if (inviteDisplay) inviteDisplay.style.display = 'none';
return;
}
if (response.linked) {
if (dot) dot.style.background = 'var(--green)';
text.textContent = 'Linked';
if (response.lastSyncedAt) {
if (lastSynced) lastSynced.textContent = 'Last synced ' + timeAgo(response.lastSyncedAt);
} else if (lastSynced) lastSynced.textContent = '';
if (response.invite) {
if (btnCopy) btnCopy.style.display = '';
if (inviteDisplay) {
inviteDisplay.textContent = response.invite;
inviteDisplay.style.display = 'block';
}
} else {
if (btnCopy) btnCopy.style.display = 'none';
if (inviteDisplay) inviteDisplay.style.display = 'none';
}
const card = $('syncLinkedDevicesCard');
const tbody = $('syncLinkedDevicesTable');
if (card) card.style.display = 'block';
if (tbody) {
const syncGroupId = response.syncGroupId || '—';
const linkedDevices = Array.isArray(response.linkedDevices) ? response.linkedDevices : [];
if (linkedDevices.length > 0) linkedDevices.sort((a, b) => (a.id || '').localeCompare(b.id || ''));
let rows = '';
if (linkedDevices.length > 0) {
linkedDevices.forEach((d, i) => {
const label = d.isCurrent ? 'This device' : ('Device ' + (i + 1));
rows += '
| ' + escapeHtml(label) + ' | ' + escapeHtml(d.id || '—') + ' |
';
});
} else {
rows = '| This device | ' + escapeHtml(response.deviceId || '—') + ' |
';
}
rows += '| Sync group | ' + escapeHtml(syncGroupId) + ' |
';
tbody.innerHTML = rows;
}
} else {
if (dot) dot.style.background = 'var(--text4)';
text.textContent = 'Not linked';
if (lastSynced) lastSynced.textContent = '';
if (btnCopy) btnCopy.style.display = 'none';
if (inviteDisplay) inviteDisplay.style.display = 'none';
const card = $('syncLinkedDevicesCard');
const tbody = $('syncLinkedDevicesTable');
if (card) card.style.display = 'none';
if (tbody) tbody.innerHTML = '| Not linked |
';
}
}
);
}
/**
* Attach event listeners for the Sync page.
*/
function setupSyncEvents() {
const btnCreate = $('btnCreateSyncInvite');
const btnCopy = $('btnCopyInvite');
const btnPair = $('btnPairWithInvite');
const inviteInput = $('syncInviteInput');
const inviteDisplay = $('syncInviteDisplay');
btnCreate?.addEventListener('click', () => {
if (btnCreate.disabled) return;
btnCreate.disabled = true;
btnCreate.textContent = 'Creating…';
chrome.runtime.sendMessage(
{ target: 'holesail-native', action: 'send', payload: { type: 'createSyncInvite' } },
(response) => {
btnCreate.disabled = false;
btnCreate.textContent = 'Create invite';
if (chrome.runtime.lastError) {
showToast('Failed: ' + (chrome.runtime.lastError.message || 'unknown'), 'error');
return;
}
if (response && response.ok && response.invite) {
inviteDisplay.style.display = 'block';
inviteDisplay.textContent = response.invite;
btnCopy.style.display = '';
showToast('Invite created. Share it with the other device.', 'success');
updateSyncStatus();
} else {
showToast(response && response.error ? response.error : 'Failed to create invite', 'error');
}
}
);
});
btnCopy?.addEventListener('click', () => {
if (!inviteDisplay || !inviteDisplay.textContent) return;
navigator.clipboard.writeText(inviteDisplay.textContent).then(() => {
showToast('Invite copied to clipboard', 'success');
}).catch(() => {
showToast('Copy failed', 'error');
});
});
btnPair?.addEventListener('click', () => {
const invite = inviteInput?.value?.trim();
if (!invite) {
showToast('Paste an invite first', 'error');
return;
}
const errEl = $('linkDeviceError');
if (errEl) { errEl.style.display = 'none'; errEl.textContent = ''; }
openModal('modal-linkDevice');
});
$('linkDeviceConfirm')?.addEventListener('click', () => {
const invite = inviteInput?.value?.trim();
const errEl = $('linkDeviceError');
if (!invite) {
if (errEl) { errEl.textContent = 'Paste an invite in the field below first.'; errEl.style.display = 'block'; }
return;
}
closeModal('modal-linkDevice');
if (btnPair) { btnPair.disabled = true; btnPair.textContent = 'Linking…'; }
chrome.runtime.sendMessage(
{ target: 'holesail-native', action: 'send', payload: { type: 'pairWithInvite', payload: { invite } } },
(response) => {
if (btnPair) { btnPair.disabled = false; btnPair.textContent = 'Link device'; }
if (chrome.runtime.lastError) {
showToast('Failed: ' + (chrome.runtime.lastError.message || 'unknown'), 'error');
return;
}
if (response && response.ok) {
showToast('Device linked. State has been synced.', 'success');
if (inviteInput) inviteInput.value = '';
updateSyncStatus();
if (typeof refresh === 'function') refresh();
} else {
showToast(response && response.error ? response.error : 'Linking failed', 'error');
}
}
);
});
}