Skip to content

Commit cd9dbd3

Browse files
committed
fix: scope profile edit drafts per user and clear them on save
1 parent 2c4906b commit cd9dbd3

1 file changed

Lines changed: 21 additions & 9 deletions

File tree

templates/v3/user_profile_edit.html

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,11 @@
282282

283283

284284
document.addEventListener('alpine:init', () => {
285+
// Draft keys are scoped to the logged-in user so drafts never leak across
286+
// accounts sharing the same browser.
287+
const TAGLINE_DRAFT_KEY = 'boost:editUser:taglineDraft:{{ request.user.pk }}';
288+
const BIO_DRAFT_KEY = 'boost:editUser:bioDraft:{{ request.user.pk }}';
289+
285290
window.createTagline = function () {
286291
const taglineInput = document.querySelector("input[name='{{user_profile_form.tagline.name}}']")
287292

@@ -297,7 +302,7 @@
297302
},
298303

299304
taglineDraftKey() {
300-
return 'boost:editUser:taglineDraft';
305+
return TAGLINE_DRAFT_KEY;
301306
},
302307

303308
onTaglineEdited() {
@@ -347,23 +352,24 @@
347352
contentLength: 0,
348353
contentSaveStatus: '', // same states, for the Content field
349354
_contentSaveTimer: null,
355+
_draftRestored: false,
350356
errors: {
351357
content: '{{ user_profile_form.bio.errors.0|default:""|escapejs }}',
352358
},
353359

354-
355-
async init() {
356-
await Alpine.nextTick()
357-
this.restoreContentDraft();
358-
},
359-
360360
// Bridge from the WYSIWYG editor: keep the counter, indicator, and draft
361361
// in sync. Programmatic updates (initial load / restore) skip the
362362
// "Saving to draft" animation and persistence.
363363
handleWysiwygUpdate(e) {
364364
if (e.detail.id !== 'field-content') return;
365365
this.contentLength = e.detail.markdownCharacters;
366366
this.content = e.detail.value;
367+
// The first (programmatic) update signals the editor is mounted —
368+
// restoring any sooner would dispatch into a not-yet-created editor.
369+
if (!this._draftRestored) {
370+
this._draftRestored = true;
371+
this.restoreContentDraft();
372+
}
367373
if (!e.detail.programmatic) {
368374
this.onContentEdited();
369375
}
@@ -376,9 +382,9 @@
376382
}));
377383
},
378384

379-
// ── Content draft: localStorage, keyed per post type (mirrors Description) ──
385+
// ── Content draft: localStorage, keyed per user (mirrors Tagline) ──
380386
contentDraftKey() {
381-
return 'boost:userEdit:bioDraft:' + (this.postType || '');
387+
return BIO_DRAFT_KEY;
382388
},
383389

384390
onContentEdited(e) {
@@ -567,6 +573,12 @@
567573
throw new Error(fieldErrors.length ? fieldErrors.join(' ') : `Save failed (${res.status})`);
568574
}
569575
this.saveStatus = 'saved';
576+
// The server now holds these values; drop the drafts so they can't
577+
// shadow the saved data on the next visit.
578+
try {
579+
localStorage.removeItem(TAGLINE_DRAFT_KEY);
580+
localStorage.removeItem(BIO_DRAFT_KEY);
581+
} catch (_) {}
570582
} catch (err) {
571583
console.error('Profile save failed:', err);
572584
this.saveStatus = 'error';

0 commit comments

Comments
 (0)