+29
-6
src/components/organisms/grain-profile-header.js
+29
-6
src/components/organisms/grain-profile-header.js
···
238
238
if (!this._user || this._followLoading || !this.profile) return;
239
239
240
240
this._followLoading = true;
241
+
242
+
// Store previous state for rollback
243
+
const previousState = {
244
+
viewerIsFollowing: this.profile.viewerIsFollowing,
245
+
viewerFollowUri: this.profile.viewerFollowUri,
246
+
followerCount: this.profile.followerCount || 0
247
+
};
248
+
249
+
// Optimistic update - apply immediately
250
+
const newIsFollowing = !previousState.viewerIsFollowing;
251
+
this.profile = {
252
+
...this.profile,
253
+
viewerIsFollowing: newIsFollowing,
254
+
viewerFollowUri: newIsFollowing ? this.profile.viewerFollowUri : null,
255
+
followerCount: previousState.followerCount + (newIsFollowing ? 1 : -1)
256
+
};
257
+
241
258
try {
242
259
const update = await mutations.toggleFollow(
243
260
this.profile.handle,
244
261
this.profile.did,
245
-
this.profile.viewerIsFollowing,
246
-
this.profile.viewerFollowUri,
247
-
this.profile.followerCount || 0
262
+
previousState.viewerIsFollowing,
263
+
previousState.viewerFollowUri,
264
+
previousState.followerCount
248
265
);
266
+
// Update with real URI from server (needed for future unfollows)
249
267
this.profile = {
250
268
...this.profile,
251
-
viewerIsFollowing: update.viewerIsFollowing,
252
-
viewerFollowUri: update.viewerFollowUri,
253
-
followerCount: update.followerCount
269
+
viewerFollowUri: update.viewerFollowUri
254
270
};
255
271
} catch (err) {
272
+
// Rollback on failure
256
273
console.error('Failed to toggle follow:', err);
274
+
this.profile = {
275
+
...this.profile,
276
+
viewerIsFollowing: previousState.viewerIsFollowing,
277
+
viewerFollowUri: previousState.viewerFollowUri,
278
+
followerCount: previousState.followerCount
279
+
};
257
280
this.shadowRoot.querySelector('grain-toast')?.show('Failed to update');
258
281
} finally {
259
282
this._followLoading = false;