Skip to content

Commit

Permalink
Merge pull request #283 from braden-w:feature/whi-99-feat-attempt-to-…
Browse files Browse the repository at this point in the history
…merge-old-settings-with-default-settings

feat: attempt to merge old settings with default settings when settings schema is updated
  • Loading branch information
braden-w authored Aug 12, 2024
2 parents 6903d4f + 5e7f470 commit e545c84
Showing 1 changed file with 53 additions and 22 deletions.
75 changes: 53 additions & 22 deletions apps/app/src/lib/utils/createPersistedState.svelte.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { renderErrorAsToast } from '$lib/services/renderErrorAsToast';
import { toast } from '$lib/services/ToastService';
import { Schema as S } from '@effect/schema';
import { WhisperingError } from '@repo/shared';
import { Effect } from 'effect';
import { Effect, Either } from 'effect';
import { nanoid } from 'nanoid/non-secure';

/**
* Creates a persisted state object tied to local storage, accessible through `.value`
Expand Down Expand Up @@ -42,28 +42,59 @@ export function createPersistedState<TSchema extends S.Schema.AnyNoContext>({
}) {
let value = $state(defaultValue);

const parseValueFromStorage = (valueFromStorage: string | null): S.Schema.Type<TSchema> => {
const isEmpty = valueFromStorage === null;
const parseValueFromStorage = (
valueFromStorageUnparsed: string | null,
): S.Schema.Type<TSchema> => {
const isEmpty = valueFromStorageUnparsed === null;
if (isEmpty) return defaultValue;
const jsonSchema = S.parseJson(schema);
const parseResult = S.decodeUnknown(jsonSchema)(valueFromStorage)
.pipe(
Effect.mapError(
(e) =>
new WhisperingError({
variant: 'warning',
title: `Invalid value from storage for key "${key}", using default value instead.`,
description: e.message,
}),
const maybeParsedValue = S.decodeUnknownEither(jsonSchema)(valueFromStorageUnparsed);
if (Either.isRight(maybeParsedValue)) {
const parsedValue = maybeParsedValue.right;
return parsedValue as S.Schema.Type<TSchema>;
}

return Effect.gen(function* () {
const updatingLocalStorageToastId = nanoid();
yield* toast({
variant: 'loading',
title: `Updating "${key}" in local storage...`,
description: 'Please wait...',
});
// Attempt to merge the default value with the value from storage if possible
const oldValueFromStorageMaybeInvalid = yield* S.decodeUnknown(S.parseJson(S.Any))(
valueFromStorageUnparsed,
);
const defaultValueMergedOldValues = {
...defaultValue,
...oldValueFromStorageMaybeInvalid,
};

const updatedValue: S.Schema.Type<TSchema> = yield* S.decodeUnknown(schema)(
defaultValueMergedOldValues,
).pipe(
Effect.tap(() =>
toast({
id: updatingLocalStorageToastId,
variant: 'success',
title: `Successfully updated "${key}" in local storage`,
description: 'The value has been updated.',
}),
),
Effect.tapError(renderErrorAsToast),
Effect.catchAll(() => {
localStorage.setItem(key, JSON.stringify(defaultValue));
return Effect.succeed(defaultValue);
}),
)
.pipe(Effect.runSync);
return parseResult as S.Schema.Type<TSchema>;
Effect.tapError(() =>
toast({
id: updatingLocalStorageToastId,
variant: 'error',
title: `Error updating "${key}" in local storage`,
description: 'Reverting to default value.',
}),
),
Effect.catchAll(() => Effect.succeed(defaultValue)),
);

localStorage.setItem(key, JSON.stringify(updatedValue));
return updatedValue;
}).pipe(Effect.runSync);
};

if (!disableLocalStorage) {
Expand Down

0 comments on commit e545c84

Please sign in to comment.