js/inbox.js

Code: DEV-8642FAC0 Size: 13.3 KB Lines: 247 Path: /home/prodconfig.wenesthosting.com/dev.solargroup.wenest.se/js/inbox.js

Task / Comment

Open report form
// gmail.js - Gmail client

// === GMAIL CLIENT ===
let gmailLabel = 'INBOX';
let gmailNextPage = null;
let gmailCurrentId = null;

async function loadGmailInbox(pageToken) {
    if (!await ensureToken()) { updateAuthUI(); return; }
    const list = document.getElementById('mailList');
    const loading = document.getElementById('mailListLoading');
    if (loading) loading.style.display = 'block';

    const search = document.getElementById('mailSearch')?.value || '';
    const params = { action: 'list', accessToken: gAccessToken, label: gmailLabel, maxResults: 25 };
    if (search) params.q = search;
    if (pageToken) params.pageToken = pageToken;

    try {
        const res = await fetch('/api/gmail-proxy.php', {
            method: 'POST',
            headers: {'Content-Type': 'application/json'},
            body: JSON.stringify(params)
        });
        const data = await res.json();
        if (data.error === 'TOKEN_EXPIRED') { gAccessToken = ''; updateAuthUI(); return; }
        if (data.error) throw new Error(data.error);

        gmailNextPage = data.nextPageToken;
        const count = document.getElementById('mailCount');
        if (count) count.textContent = (data.resultSizeEstimate || 0) + ' meddelanden';

        if (list) {
            list.innerHTML = data.messages.map(m => {
                const fromName = m.from.replace(/<.*>/, '').trim() || m.from;
                const isActive = m.id === gmailCurrentId;
                return '<div onclick="readGmail(\'' + m.id + '\')" style="padding:12px 16px;border-bottom:1px solid #f1f5f9;cursor:pointer;background:' + (isActive ? '#eff6ff' : (m.unread ? '#fefce8' : '#fff')) + ';transition:background .15s' + '">'
                    + '<div style="display:flex;justify-content:space-between;align-items:start">'
                    + '<strong style="font-size:13px;font-weight:' + (m.unread ? '700' : '500') + ';color:#1a1a1a;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:220px">' + escHtml(fromName) + '</strong>'
                    + '<span style="font-size:11px;color:#94a3b8;white-space:nowrap;margin-left:8px">' + formatMailDate(m.timestamp) + '</span>'
                    + '</div>'
                    + '<div style="font-size:13px;color:#334155;font-weight:' + (m.unread ? '600' : '400') + ';overflow:hidden;text-overflow:ellipsis;white-space:nowrap;margin-top:2px">' + escHtml(m.subject) + '</div>'
                    + '<div style="font-size:12px;color:#94a3b8;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;margin-top:2px">' + escHtml(m.snippet) + '</div>'
                    + '</div>';
            }).join('');
        }

        // Pagination
        const pag = document.getElementById('mailPagination');
        if (pag) {
            pag.innerHTML = gmailNextPage
                ? '<button onclick="loadGmailInbox(\'' + gmailNextPage + '\')" style="padding:6px 16px;background:#f1f5f9;border:1px solid #e5e7eb;border-radius:6px;font-size:12px;cursor:pointer;font-family:inherit">Visa fler</button>'
                : '';
        }
    } catch(e) {
        if (list) list.innerHTML = '<div style="padding:20px;text-align:center;color:#ef4444;font-size:13px">' + e.message + '</div>';
    }
    if (loading) loading.style.display = 'none';
}

async function readGmail(id) {
    if (!await ensureToken()) return;
    gmailCurrentId = id;
    // Highlight in list
    loadGmailInbox();

    const content = document.getElementById('mailReaderContent');
    const empty = document.getElementById('mailReaderEmpty');
    if (empty) empty.style.display = 'none';
    if (content) { content.style.display = 'block'; content.innerHTML = '<div style="text-align:center;padding:40px;color:#94a3b8">Laddar...</div>'; }

    try {
        const res = await fetch('/api/gmail-proxy.php', {
            method: 'POST',
            headers: {'Content-Type': 'application/json'},
            body: JSON.stringify({ action: 'read', accessToken: gAccessToken, id })
        });
        const data = await res.json();
        if (data.error) throw new Error(data.error);

        const fromName = data.from.replace(/<.*>/, '').trim();
        const fromEmail = (data.from.match(/<(.+)>/) || ['', data.from])[1];
        const dateStr = new Date(data.timestamp * 1000).toLocaleString('sv-SE');

        content.innerHTML = '<div style="margin-bottom:20px">'
            + '<h2 style="font-size:18px;font-weight:700;color:#1a1a1a;margin-bottom:12px">' + escHtml(data.subject) + '</h2>'
            + '<div style="display:flex;justify-content:space-between;align-items:start;flex-wrap:wrap;gap:8px">'
            + '<div><strong style="font-size:14px">' + escHtml(fromName) + '</strong><br><span style="font-size:12px;color:#64748b">' + escHtml(fromEmail) + '</span>'
            + (data.cc ? '<br><span style="font-size:12px;color:#94a3b8">Cc: ' + escHtml(data.cc) + '</span>' : '') + '</div>'
            + '<span style="font-size:12px;color:#94a3b8">' + dateStr + '</span>'
            + '</div>'
            + '<div style="display:flex;gap:6px;margin-top:12px">'
            + '<button onclick="mailReply(\'' + id + '\')" style="padding:6px 14px;background:#024550;color:#fff;border:none;border-radius:6px;font-size:12px;font-weight:600;cursor:pointer;font-family:inherit">Svara</button>'
            + '<button onclick="mailForward(\'' + id + '\')" style="padding:6px 14px;background:#f1f5f9;color:#334155;border:1px solid #e5e7eb;border-radius:6px;font-size:12px;cursor:pointer;font-family:inherit">Vidarebefordra</button>'
            + '<button onclick="mailTrash(\'' + id + '\')" style="padding:6px 14px;background:#fef2f2;color:#991b1b;border:1px solid #fecaca;border-radius:6px;font-size:12px;cursor:pointer;font-family:inherit">Radera</button>'
            + '</div>'
            + '</div>'
            + (data.attachments.length ? '<div style="padding:8px 12px;background:#f8fafc;border-radius:8px;margin-bottom:12px;border:1px solid #e5e7eb"><span style="font-size:12px;font-weight:600;color:#334155">Bilagor: </span>' + data.attachments.map(a => '<span style="font-size:12px;color:#3b82f6">' + escHtml(a.filename) + ' (' + formatSize(a.size) + ')</span>').join(', ') + '</div>' : '')
            + '<div style="border-top:1px solid #e5e7eb;padding-top:16px">'
            + '<iframe id="mailBodyFrame" srcdoc="" style="width:100%;min-height:400px;border:none" sandbox="allow-same-origin"></iframe>'
            + '</div>';

        // Set iframe content
        const iframe = document.getElementById('mailBodyFrame');
        if (iframe) {
            const bodyContent = data.bodyHtml || ('<pre style="white-space:pre-wrap;font-family:sans-serif">' + escHtml(data.bodyText) + '</pre>');
            iframe.srcdoc = '<html><head><style>body{font-family:sans-serif;font-size:14px;color:#1a1a1a;margin:0;padding:0;line-height:1.5}img{max-width:100%}a{color:#0284c7}</style></head><body>' + bodyContent + '</body></html>';
        }

        // Store for reply
        window._lastMailData = data;
    } catch(e) {
        content.innerHTML = '<div style="padding:20px;color:#ef4444">' + e.message + '</div>';
    }
}

function mailCompose() {
    document.getElementById('composeTitle').textContent = 'Nytt meddelande';
    document.getElementById('composeTo').value = '';
    document.getElementById('composeCc').value = '';
    document.getElementById('composeSubject').value = '';
    document.getElementById('composeBody').value = '';
    document.getElementById('composeReplyUid').value = '0';
    document.getElementById('composeReplyFolder').value = '';
    document.getElementById('composeReplyTo').value = '';
    document.getElementById('composeSignature').value = gMailSignature || '--\nMed vänliga hälsningar\n' + gUserName + '\nSolargroup';
    document.getElementById('mailComposeModal').style.display = 'flex';
}

function mailReply(id) {
    const d = window._lastMailData;
    if (!d) return;
    document.getElementById('composeTitle').textContent = 'Svara';
    document.getElementById('composeTo').value = d.replyTo || d.from;
    document.getElementById('composeCc').value = '';
    document.getElementById('composeSubject').value = (d.subject.startsWith('Re:') ? '' : 'Re: ') + d.subject;
    document.getElementById('composeBody').value = '\n\n--- Ursprungligt meddelande ---\nFrån: ' + d.from + '\nDatum: ' + new Date(d.timestamp*1000).toLocaleString('sv-SE') + '\n\n' + (d.bodyText || '');
    document.getElementById('composeReplyUid').value = id;
    document.getElementById('composeReplyTo').value = d.messageId || '';
    document.getElementById('composeSignature').value = gMailSignature || '--\nMed vänliga hälsningar\n' + gUserName;
    document.getElementById('mailComposeModal').style.display = 'flex';
}

function mailForward(id) {
    const d = window._lastMailData;
    if (!d) return;
    document.getElementById('composeTitle').textContent = 'Vidarebefordra';
    document.getElementById('composeTo').value = '';
    document.getElementById('composeCc').value = '';
    document.getElementById('composeSubject').value = 'Fwd: ' + d.subject;
    document.getElementById('composeBody').value = '\n\n--- Vidarebefordrat meddelande ---\nFrån: ' + d.from + '\nTill: ' + d.to + '\nDatum: ' + new Date(d.timestamp*1000).toLocaleString('sv-SE') + '\nÄmne: ' + d.subject + '\n\n' + (d.bodyText || '');
    document.getElementById('composeReplyUid').value = '0';
    document.getElementById('composeReplyTo').value = '';
    document.getElementById('composeSignature').value = gMailSignature || '--\nMed vänliga hälsningar\n' + gUserName;
    document.getElementById('mailComposeModal').style.display = 'flex';
}

async function mailSend() {
    if (!await ensureToken()) return;
    const btn = document.getElementById('composeSendBtn');
    btn.textContent = 'Skickar...'; btn.disabled = true;
    try {
        const sig = document.getElementById('composeSignature').value.trim();
        // Save signature for next time
        if (sig !== gMailSignature) {
            gMailSignature = sig;
            localStorage.setItem('mailSignature', sig);
            fetch('/api/gmail-proxy.php', {
                method: 'POST', headers: {'Content-Type': 'application/json'},
                body: JSON.stringify({ action: 'signature', staffId: gStaffId, signature: sig })
            });
        }
        const replyTo = document.getElementById('composeReplyTo').value;
        const res = await fetch('/api/gmail-proxy.php', {
            method: 'POST', headers: {'Content-Type': 'application/json'},
            body: JSON.stringify({
                action: 'send', accessToken: gAccessToken,
                to: document.getElementById('composeTo').value,
                cc: document.getElementById('composeCc').value,
                subject: document.getElementById('composeSubject').value,
                body: document.getElementById('composeBody').value,
                signature: sig,
                inReplyTo: replyTo,
                references: replyTo,
                threadId: replyTo ? (window._lastMailData?.threadId || '') : '',
            })
        });
        const data = await res.json();
        if (data.error) throw new Error(data.error);
        mailCloseCompose();
        loadGmailInbox();
    } catch(e) {
        alert('Kunde inte skicka: ' + e.message);
    }
    btn.textContent = 'Skicka'; btn.disabled = false;
}

async function mailTrash(id) {
    if (!await ensureToken()) return;
    try {
        await fetch('/api/gmail-proxy.php', {
            method: 'POST', headers: {'Content-Type': 'application/json'},
            body: JSON.stringify({ action: 'trash', accessToken: gAccessToken, id })
        });
        gmailCurrentId = null;
        document.getElementById('mailReaderContent').style.display = 'none';
        document.getElementById('mailReaderEmpty').style.display = 'flex';
        loadGmailInbox();
    } catch(e) { alert(e.message); }
}

function mailCloseCompose() { document.getElementById('mailComposeModal').style.display = 'none'; }

function mailRefresh() { loadGmailInbox(); }

function mailSwitchFolder() {
    gmailLabel = document.getElementById('mailFolderSelect').value;
    gmailCurrentId = null;
    document.getElementById('mailReaderContent').style.display = 'none';
    document.getElementById('mailReaderEmpty').style.display = 'flex';
    loadGmailInbox();
}

async function loadGmailLabels() {
    if (!await ensureToken()) return;
    try {
        const res = await fetch('/api/gmail-proxy.php', {
            method: 'POST', headers: {'Content-Type': 'application/json'},
            body: JSON.stringify({ action: 'labels', accessToken: gAccessToken })
        });
        const data = await res.json();
        const select = document.getElementById('mailFolderSelect');
        if (select && data.labels) {
            const labelNames = { INBOX: 'Inkorg', SENT: 'Skickat', DRAFTS: 'Utkast', TRASH: 'Papperskorg', SPAM: 'Skräppost', STARRED: 'Stjärnmärkt', IMPORTANT: 'Viktigt' };
            const show = data.labels.filter(l => ['INBOX','SENT','DRAFTS','TRASH','SPAM','STARRED','IMPORTANT'].includes(l.id) || l.type === 'user');
            select.innerHTML = show.map(l => '<option value="' + l.id + '"' + (l.id === gmailLabel ? ' selected' : '') + '>' + (labelNames[l.id] || l.name) + '</option>').join('');
        }
    } catch(e) {}
}

function mailDisconnect() {
    gAccessToken = '';
    sessionStorage.removeItem('gAccessToken');
    sessionStorage.removeItem('gTokenExpiry');
    updateAuthUI();
}