Skip to content

Commit 478690c

Browse files
committed
tidying up
1 parent 806f0d0 commit 478690c

File tree

7 files changed

+217
-3
lines changed

7 files changed

+217
-3
lines changed

app.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { persistDiagramState, saveToDatabase, getCurrentShortCode, loadFromDatab
99
import { initAiButton } from './js/ai.js';
1010
import { restoreSession, onAuthChange, isLoggedIn, renderAuthUI, initGoogleSignIn } from './js/auth.js';
1111
import { initDiagramsPanel } from './js/diagrams-panel.js';
12+
import { trackSaveDiagram } from './js/analytics.js';
1213

1314
const LAST_EDITED_STORAGE_KEY = 'amplistack:lastEditedAt';
1415

@@ -89,6 +90,7 @@ function setupSaveButton() {
8990
saveBtn.disabled = true;
9091
saveBtn.querySelector('span').textContent = 'Saving...';
9192
await saveToDatabase();
93+
trackSaveDiagram(document.getElementById('diagram-title')?.textContent?.trim() || 'Untitled Diagram');
9294
saveBtn.querySelector('span').textContent = 'Saved!';
9395
setTimeout(() => {
9496
saveBtn.querySelector('span').textContent = getCurrentShortCode() ? 'Save' : 'Save';

index.html

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,16 @@ <h2>My Diagrams</h2>
238238
// Set your Google OAuth Client ID here:
239239
window.AMPLISTACK_GOOGLE_CLIENT_ID = '879273734608-1mhhs92c9dbdqvs2jc4plq3f62pn2ao4.apps.googleusercontent.com';
240240
</script>
241+
<div class="confirm-dialog" id="confirm-dialog" role="dialog" aria-modal="true" hidden>
242+
<div class="confirm-dialog__content">
243+
<h3 class="confirm-dialog__title" id="confirm-dialog-title">Are you sure?</h3>
244+
<p class="confirm-dialog__message" id="confirm-dialog-message"></p>
245+
<div class="confirm-dialog__actions">
246+
<button type="button" class="confirm-dialog__btn confirm-dialog__btn--cancel" id="confirm-dialog-cancel">Cancel</button>
247+
<button type="button" class="confirm-dialog__btn confirm-dialog__btn--confirm" id="confirm-dialog-confirm">Delete</button>
248+
</div>
249+
</div>
250+
</div>
241251
<div class="ai-dialog" id="ai-dialog" role="dialog" aria-modal="true" aria-labelledby="ai-dialog-title" hidden>
242252
<div class="ai-dialog__content">
243253
<h2 id="ai-dialog-title">Generate with AI</h2>

js/analytics.js

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,3 +37,76 @@ export function trackAppLaunched() {
3737
console.warn('Failed to track App Launched', err);
3838
}
3939
}
40+
41+
export function trackOpenedTemplate(templateName) {
42+
try {
43+
const amp = window?.amplitude;
44+
const props = { 'template name': templateName };
45+
if (amp?.track) {
46+
amp.track('Opened Template', props);
47+
} else if (amp?.getInstance) {
48+
amp.getInstance().logEvent?.('Opened Template', props);
49+
}
50+
} catch (err) {
51+
console.warn('Failed to track Opened Template', err);
52+
}
53+
}
54+
55+
export function trackLoggedIn(name) {
56+
try {
57+
const amp = window?.amplitude;
58+
if (amp?.track) {
59+
amp.track('Logged In');
60+
} else if (amp?.getInstance) {
61+
amp.getInstance().logEvent?.('Logged In');
62+
}
63+
// Set user property
64+
const identify = new window.amplitude.Identify().set('name', name);
65+
if (amp?.identify) {
66+
amp.identify(identify);
67+
}
68+
} catch (err) {
69+
console.warn('Failed to track Logged In', err);
70+
}
71+
}
72+
73+
export function trackSaveDiagram(diagramName) {
74+
try {
75+
const amp = window?.amplitude;
76+
const props = { 'diagram name': diagramName };
77+
if (amp?.track) {
78+
amp.track('Save Diagram', props);
79+
} else if (amp?.getInstance) {
80+
amp.getInstance().logEvent?.('Save Diagram', props);
81+
}
82+
} catch (err) {
83+
console.warn('Failed to track Save Diagram', err);
84+
}
85+
}
86+
87+
export function trackLoggedOut() {
88+
try {
89+
const amp = window?.amplitude;
90+
if (amp?.track) {
91+
amp.track('Logged Out');
92+
} else if (amp?.getInstance) {
93+
amp.getInstance().logEvent?.('Logged Out');
94+
}
95+
} catch (err) {
96+
console.warn('Failed to track Logged Out', err);
97+
}
98+
}
99+
100+
export function trackOpenDiagram(diagramName) {
101+
try {
102+
const amp = window?.amplitude;
103+
const props = { 'diagram name': diagramName };
104+
if (amp?.track) {
105+
amp.track('Open Diagram', props);
106+
} else if (amp?.getInstance) {
107+
amp.getInstance().logEvent?.('Open Diagram', props);
108+
}
109+
} catch (err) {
110+
console.warn('Failed to track Open Diagram', err);
111+
}
112+
}

js/auth.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import { trackLoggedIn, trackLoggedOut } from './analytics.js';
2+
13
const TOKEN_KEY = 'amplistack-auth-token';
24
const USER_KEY = 'amplistack-auth-user';
35

@@ -50,11 +52,13 @@ export async function handleGoogleCredential(credential) {
5052
currentUser = data.user;
5153
localStorage.setItem(TOKEN_KEY, authToken);
5254
localStorage.setItem(USER_KEY, JSON.stringify(currentUser));
55+
trackLoggedIn(currentUser.name);
5356
notifyAuthChange();
5457
return currentUser;
5558
}
5659

5760
export function logout() {
61+
trackLoggedOut();
5862
currentUser = null;
5963
authToken = null;
6064
localStorage.removeItem(TOKEN_KEY);

js/diagrams-panel.js

Lines changed: 48 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { isLoggedIn, onAuthChange } from './auth.js';
2+
import { trackOpenDiagram } from './analytics.js';
23
import { listDiagrams, duplicateDiagram, deleteDiagram } from './api.js';
34
import { getCurrentShortCode } from './persistence.js';
45

@@ -94,6 +95,9 @@ function renderDiagramsList(list) {
9495
btn.addEventListener('click', (e) => {
9596
e.stopPropagation();
9697
const code = btn.dataset.code;
98+
const card = btn.closest('.diagram-card');
99+
const title = card?.querySelector('.diagram-card-title')?.textContent || 'Untitled Diagram';
100+
trackOpenDiagram(title);
97101
window.location.href = `${window.location.pathname}?d=${code}`;
98102
});
99103
});
@@ -102,14 +106,18 @@ function renderDiagramsList(list) {
102106
btn.addEventListener('click', async (e) => {
103107
e.stopPropagation();
104108
const code = btn.dataset.code;
105-
if (!confirm('Delete this diagram? This cannot be undone.')) return;
109+
const confirmed = await showConfirmDialog(
110+
'Delete diagram?',
111+
'This diagram will be permanently deleted. This cannot be undone.'
112+
);
113+
if (!confirmed) return;
106114
try {
107115
btn.disabled = true;
108116
btn.textContent = 'Deleting...';
109117
await deleteDiagram(code);
110118
await refreshDiagramsList();
111119
} catch (err) {
112-
alert('Failed to delete diagram');
120+
showConfirmDialog('Delete failed', 'Could not delete this diagram. Please try again.', true);
113121
btn.disabled = false;
114122
btn.textContent = 'Delete';
115123
}
@@ -134,6 +142,44 @@ function renderDiagramsList(list) {
134142
});
135143
}
136144

145+
function showConfirmDialog(title, message, infoOnly = false) {
146+
return new Promise((resolve) => {
147+
const dialog = document.getElementById('confirm-dialog');
148+
const titleEl = document.getElementById('confirm-dialog-title');
149+
const messageEl = document.getElementById('confirm-dialog-message');
150+
const cancelBtn = document.getElementById('confirm-dialog-cancel');
151+
const confirmBtn = document.getElementById('confirm-dialog-confirm');
152+
if (!dialog) { resolve(!infoOnly && confirm(message)); return; }
153+
154+
titleEl.textContent = title;
155+
messageEl.textContent = message;
156+
157+
if (infoOnly) {
158+
cancelBtn.style.display = 'none';
159+
confirmBtn.textContent = 'OK';
160+
confirmBtn.className = 'confirm-dialog__btn confirm-dialog__btn--cancel';
161+
} else {
162+
cancelBtn.style.display = '';
163+
confirmBtn.textContent = 'Delete';
164+
confirmBtn.className = 'confirm-dialog__btn confirm-dialog__btn--confirm';
165+
}
166+
167+
dialog.hidden = false;
168+
169+
function cleanup(result) {
170+
dialog.hidden = true;
171+
cancelBtn.removeEventListener('click', onCancel);
172+
confirmBtn.removeEventListener('click', onConfirm);
173+
resolve(result);
174+
}
175+
function onCancel() { cleanup(false); }
176+
function onConfirm() { cleanup(true); }
177+
178+
cancelBtn.addEventListener('click', onCancel);
179+
confirmBtn.addEventListener('click', onConfirm);
180+
});
181+
}
182+
137183
function escapeHtml(str) {
138184
const div = document.createElement('div');
139185
div.textContent = str;

js/nodes.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ import {
4343
parseCustomConnectionKey,
4444
renderConnections
4545
} from './connections.js';
46-
import { trackAppLaunched, trackExportButtonClick, trackNodeAdded } from './analytics.js';
46+
import { trackAppLaunched, trackExportButtonClick, trackNodeAdded, trackOpenedTemplate } from './analytics.js';
4747
import {
4848
clearPersistedDiagramState,
4949
loadDiagramState,
@@ -917,6 +917,7 @@ function initTemplateButtons() {
917917
const template = btn.dataset.template;
918918
const url = TEMPLATE_URLS[template];
919919
if (url) {
920+
trackOpenedTemplate(btn.textContent.trim());
920921
window.location.href = url;
921922
}
922923
});

styles.css

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1653,6 +1653,84 @@ body {
16531653
background: #FDE68A;
16541654
}
16551655

1656+
/* Confirm Dialog */
1657+
.confirm-dialog {
1658+
position: fixed;
1659+
inset: 0;
1660+
display: flex;
1661+
align-items: center;
1662+
justify-content: center;
1663+
background: rgba(0, 0, 0, 0.4);
1664+
z-index: 10000;
1665+
padding: 16px;
1666+
}
1667+
1668+
.confirm-dialog[hidden] {
1669+
display: none;
1670+
}
1671+
1672+
.confirm-dialog__content {
1673+
background: var(--color-white);
1674+
border-radius: var(--radius-lg);
1675+
max-width: 380px;
1676+
width: 100%;
1677+
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.18);
1678+
padding: 24px;
1679+
display: flex;
1680+
flex-direction: column;
1681+
gap: 8px;
1682+
}
1683+
1684+
.confirm-dialog__title {
1685+
font-size: 16px;
1686+
font-weight: 600;
1687+
color: var(--color-gray-900);
1688+
margin: 0;
1689+
}
1690+
1691+
.confirm-dialog__message {
1692+
font-size: 14px;
1693+
color: var(--color-gray-600);
1694+
margin: 0;
1695+
line-height: 1.5;
1696+
}
1697+
1698+
.confirm-dialog__actions {
1699+
display: flex;
1700+
justify-content: flex-end;
1701+
gap: 8px;
1702+
margin-top: 12px;
1703+
}
1704+
1705+
.confirm-dialog__btn {
1706+
padding: 8px 16px;
1707+
font-size: 14px;
1708+
font-weight: 500;
1709+
font-family: inherit;
1710+
border-radius: var(--radius-md);
1711+
border: none;
1712+
cursor: pointer;
1713+
transition: all 0.15s ease;
1714+
}
1715+
1716+
.confirm-dialog__btn--cancel {
1717+
background: var(--color-gray-100);
1718+
color: var(--color-gray-700);
1719+
}
1720+
1721+
.confirm-dialog__btn--cancel:hover {
1722+
background: var(--color-gray-200);
1723+
}
1724+
1725+
.confirm-dialog__btn--confirm {
1726+
background: #DC2626;
1727+
color: var(--color-white);
1728+
}
1729+
1730+
.confirm-dialog__btn--confirm:hover {
1731+
background: #B91C1C;
1732+
}
1733+
16561734
/* Responsive adjustments */
16571735
@media (max-width: 1024px) {
16581736
:root {

0 commit comments

Comments
 (0)