send user prefs data in broadcast msg (#1466)

fixes #1464 

The user preference changes were not broadcasting correctly in firefox
because it has a race condition wherein the broadcast message was being
received by a peer tab before the localStorage data was ready to be
consumed in that tab.

### Change Type

<!-- 💡 Indicate the type of change your pull request is. -->
<!-- 🤷‍♀️ If you're not sure, don't select anything -->
<!-- ✂️ Feel free to delete unselected options -->

<!-- To select one, put an x in the box: [x] -->

- [x] `patch` — Bug Fix
- [ ] `minor` — New Feature
- [ ] `major` — Breaking Change
- [ ] `dependencies` — Dependency Update (publishes a `patch` release,
for devDependencies use `internal`)
- [ ] `documentation` — Changes to the documentation only (will not
publish a new version)
- [ ] `tests` — Changes to any testing-related code only (will not
publish a new version)
- [ ] `internal` — Any other changes that don't affect the published
package (will not publish a new version)

### Test Plan

1. in firefox, have two tabs open in the same user context.
2. toggle dark mode.
3. the change should propagate to the other tab
This commit is contained in:
David Sheldrick 2023-05-25 16:36:29 +01:00 committed by GitHub
parent f551528ddf
commit b742783577
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -27,18 +27,16 @@ interface UserDataSnapshot {
interface UserChangeBroadcastMessage {
type: typeof broadcastEventKey
origin: string
data: UserDataSnapshot
}
const userTypeValidator: T.Validator<TLUserPreferences> = T.model(
'user',
T.object({
const userTypeValidator: T.Validator<TLUserPreferences> = T.object({
id: T.string,
name: T.string,
locale: T.string,
color: T.string,
isDarkMode: T.boolean,
})
)
const userTypeMigrations = defineMigrations({})
@ -72,18 +70,12 @@ function getFreshUserPreferences(): TLUserPreferences {
isDarkMode: false,
}
}
function loadUserPreferences(): TLUserPreferences {
const userData =
typeof window === 'undefined'
? null
: ((JSON.parse(window?.localStorage?.getItem(USER_DATA_KEY) || 'null') ??
null) as null | UserDataSnapshot)
if (userData === null) {
function migrateUserPreferences(userData: unknown) {
if (userData === null || typeof userData !== 'object') {
return getFreshUserPreferences()
}
if (!('version' in userData) || !('user' in userData)) {
if (!('version' in userData) || !('user' in userData) || typeof userData.version !== 'number') {
return getFreshUserPreferences()
}
@ -107,6 +99,16 @@ function loadUserPreferences(): TLUserPreferences {
return migrationResult.value
}
function loadUserPreferences(): TLUserPreferences {
const userData =
typeof window === 'undefined'
? null
: ((JSON.parse(window?.localStorage?.getItem(USER_DATA_KEY) || 'null') ??
null) as null | UserDataSnapshot)
return migrateUserPreferences(userData)
}
const globalUserPreferences = atom<TLUserPreferences>('globalUserData', loadUserPreferences())
function storeUserPreferences() {
@ -138,7 +140,7 @@ const channel =
channel?.addEventListener('message', (e) => {
const data = e.data as undefined | UserChangeBroadcastMessage
if (data?.type === broadcastEventKey && data?.origin !== broadcastOrigin) {
globalUserPreferences.set(loadUserPreferences())
globalUserPreferences.set(migrateUserPreferences(data.data))
}
})
@ -149,6 +151,10 @@ function broadcastUserPreferencesChange() {
channel?.postMessage({
type: broadcastEventKey,
origin: broadcastOrigin,
data: {
user: globalUserPreferences.value,
version: userTypeMigrations.currentVersion,
},
} satisfies UserChangeBroadcastMessage)
}