Release 1.1.0: switch to dewemoji.com and simplify account UI

This commit is contained in:
Dwindi Ramadhana
2026-02-20 11:24:19 +07:00
parent bcbbab7922
commit 5a67be8f70
4 changed files with 44 additions and 70 deletions

View File

@@ -4,7 +4,7 @@ This checklist verifies extension behavior against current backend flow.
## Preconditions
- Extension loaded in Chrome (unpacked).
- Backend reachable at `https://api.dewemoji.com/v1`.
- Backend reachable at `https://dewemoji.com/v1`.
- Backend deployed with extension search route:
- `GET /v1/extension/search`
- Browser DevTools available for network/console checks.

View File

@@ -1,7 +1,7 @@
{
"name": "Dewemoji - Emojis Made Effortless",
"description": "Find and copy emojis instantly. Optional Pro license unlocks tone lock, insert mode, and more.",
"version": "1.0.2",
"description": "Find and copy emojis instantly. Connect your account to use private keywords across web and extension.",
"version": "1.1.0",
"offline_enabled": false,
"permissions": [
"storage",
@@ -12,8 +12,7 @@
],
"host_permissions": [
"<all_urls>",
"https://dewemoji.backoffice.biz.id/*",
"https://api.dewemoji.com/*"
"https://dewemoji.com/*"
],
"web_accessible_resources": [
{

View File

@@ -87,33 +87,33 @@
<div id="tab-pro" class="tabpane">
<div class="field">
<label class="lbl">Account</label>
<div class="row">
<input id="account-email" class="inp" placeholder="Email" type="email" autocomplete="username">
<div id="account-connect-form">
<div class="row">
<input id="account-email" class="inp" placeholder="Email" type="email" autocomplete="username">
</div>
<div class="row" style="margin-top:6px;">
<input id="account-password" class="inp" placeholder="Password" type="password" autocomplete="current-password">
</div>
<div class="row">
<button id="account-login" class="btn">Connect</button>
</div>
<div class="row" style="margin-top:6px;">
<span id="account-status" class="muted">Not connected. Public keywords only.</span>
</div>
</div>
<div class="row" style="margin-top:6px;">
<input id="account-password" class="inp" placeholder="Password" type="password" autocomplete="current-password">
</div>
<div class="row">
<button id="account-login" class="btn">Connect</button>
<button id="account-logout" class="btn ghost">Logout</button>
</div>
<div class="row" style="margin-top:6px;">
<span id="account-status" class="muted">Not connected. Public keywords only.</span>
<div id="account-connected" style="display:none;">
<div class="row">
<span id="account-greeting" class="muted">Connected.</span>
</div>
<div class="row" style="margin-top:8px;">
<button id="account-logout" class="btn ghost">Logout</button>
</div>
</div>
</div>
<!-- Tone settings are injected here by panel.js -->
<!-- Diagnostics -->
<div class="field">
<label class="lbl">Extension Health</label>
<div class="row">
<button id="diag-run" class="btn">Run health check</button>
<span id="diag-spin" class="muted" style="display:none;">Running…</span>
</div>
<div id="diag-out" class="diagbox muted"></div>
<p class="hint muted">Tip: Click in a text box on the page first, then run health check.</p>
</div>
</div>
</div>
@@ -136,6 +136,6 @@
</div>
<div id="toast" class="toast" role="status" aria-live="polite"></div>
<script src="panel.js?ver=1.0.1"></script>
<script src="panel.js?ver=1.1.0"></script>
</body>
</html>

View File

@@ -7,6 +7,7 @@ let licenseKeyCurrent = '';
let authApiKey = '';
let authTier = 'guest'; // guest | free | personal
let authEmail = '';
let authName = '';
// Tone settings (persisted in sync storage)
let toneLock = false; // if true, always use preferred tone
@@ -29,6 +30,9 @@ const accountPasswordEl = document.getElementById('account-password');
const accountLoginBtn = document.getElementById('account-login');
const accountLogoutBtn = document.getElementById('account-logout');
const accountStatusEl = document.getElementById('account-status');
const accountGreetingEl = document.getElementById('account-greeting');
const accountConnectFormEl = document.getElementById('account-connect-form');
const accountConnectedEl = document.getElementById('account-connected');
// --- Branded confirm modal helper ---
function showConfirmModal(opts = {}) {
@@ -113,12 +117,8 @@ function setLicenseBusy(on, label){
}
}
const diagRunBtn = document.getElementById('diag-run');
const diagSpin = document.getElementById('diag-spin');
const diagOut = document.getElementById('diag-out');
const API = {
base: "https://dewemoji.backoffice.biz.id/v1",
base: "https://dewemoji.com/v1",
list: "/emojis"
};
API.cats = "/categories";
@@ -650,8 +650,7 @@ function getListPaths(){
function getApiBases(){
const list = [
API.base,
'https://dewemoji.backoffice.biz.id/v1',
'https://api.dewemoji.com/v1',
'https://dewemoji.com/v1',
'http://127.0.0.1:8000/v1',
];
const seen = new Set();
@@ -1233,13 +1232,14 @@ loadCategories().catch(console.error);
})();
async function loadSettings() {
const data = await chrome.storage.local.get(['actionMode', 'authApiKey', 'authTier', 'authEmail']);
const data = await chrome.storage.local.get(['actionMode', 'authApiKey', 'authTier', 'authEmail', 'authName']);
licenseValid = true;
refreshPageLimit();
actionMode = data.actionMode || 'copy';
authApiKey = data.authApiKey || '';
authTier = data.authTier || 'guest';
authEmail = data.authEmail || '';
authName = data.authName || '';
if (accountEmailEl && authEmail) accountEmailEl.value = authEmail;
applyLicenseUI();
applyModeUI();
@@ -1253,7 +1253,7 @@ async function loadSettings() {
}
async function saveSettings() {
await chrome.storage.local.set({ licenseValid: true, actionMode, authApiKey, authTier, authEmail });
await chrome.storage.local.set({ licenseValid: true, actionMode, authApiKey, authTier, authEmail, authName });
}
// --- Helper to render Free status with CTA ---
@@ -1305,6 +1305,8 @@ function updateAccountUI() {
if (!accountStatusEl) return;
if (!authApiKey) {
accountStatusEl.textContent = 'Not connected. Public keywords only.';
if (accountConnectFormEl) accountConnectFormEl.style.display = '';
if (accountConnectedEl) accountConnectedEl.style.display = 'none';
if (accountLoginBtn) {
accountLoginBtn.disabled = false;
accountLoginBtn.style.display = '';
@@ -1319,7 +1321,12 @@ function updateAccountUI() {
return;
}
const tierLabel = authTier === 'personal' ? 'Personal' : 'Free';
const fallbackName = (authEmail || 'User').split('@')[0] || 'User';
const displayName = (authName || '').trim() || fallbackName;
accountStatusEl.textContent = `Connected as ${authEmail || 'user'} (${tierLabel})`;
if (accountGreetingEl) accountGreetingEl.textContent = `Hi, ${displayName}`;
if (accountConnectFormEl) accountConnectFormEl.style.display = 'none';
if (accountConnectedEl) accountConnectedEl.style.display = '';
if (accountLoginBtn) {
accountLoginBtn.disabled = true;
accountLoginBtn.style.display = 'none';
@@ -1535,6 +1542,7 @@ accountLoginBtn?.addEventListener('click', async () => {
authApiKey = data?.api_key || '';
authTier = String(data?.user?.tier || 'free');
authEmail = String(data?.user?.email || email);
authName = String(data?.user?.name || '');
await saveSettings();
updateAccountUI();
setStatusTag();
@@ -1566,6 +1574,7 @@ accountLogoutBtn?.addEventListener('click', async () => {
} finally {
authApiKey = '';
authTier = 'guest';
authName = '';
await saveSettings();
updateAccountUI();
setStatusTag();
@@ -1574,40 +1583,6 @@ accountLogoutBtn?.addEventListener('click', async () => {
}
});
async function renderDiag(obj) {
const lines = [];
lines.push(`Content script loaded: ${obj ? 'yes' : 'no'}`);
if (!obj) return lines.join('\n');
lines.push(`Active editable type: ${obj.activeType ?? 'none'}`);
lines.push(`Has caret/selection: ${obj.hasRange ? 'yes' : 'no'}`);
lines.push(`Last insert result: ${obj.lastInsertOK === null ? 'n/a' : obj.lastInsertOK ? 'success' : 'failed'}`);
if (obj.lastInsertMessage) lines.push(`Note: ${obj.lastInsertMessage}`);
return lines.join('\n');
}
async function runDiagnostics() {
diagOut.textContent = '';
diagSpin.style.display = 'inline';
try {
const [tab] = await chrome.tabs.query({ active: true, currentWindow: true });
if (!tab?.id) { diagOut.textContent = 'No active tab.'; return; }
const ready = await ensureContentScript(tab.id);
if (!ready) { diagOut.textContent = await renderDiag(null); return; }
const info = await chrome.tabs.sendMessage(tab.id, { type: 'dewemoji_diag' });
diagOut.textContent = await renderDiag(info || null);
} catch (e) {
diagOut.textContent = `Error: ${e?.message || e}`;
} finally {
diagSpin.style.display = 'none';
}
}
diagRunBtn?.addEventListener('click', () => runDiagnostics());
async function performEmojiAction(glyph) {
// Free users always copy
const mode = licenseValid ? actionMode : 'copy';