Skip to content

Commit 19e89df

Browse files
fix: clear oversized images from onboarding store during migration (calcom#27560)
* fix: clear oversized images from onboarding store during migration This fixes the 429 errors caused by large images stored in IndexedDB before PR calcom#27285 added cropping functionality. Changes: - Add version 1 to zustand persist config with migration function - Migration clears images exceeding thresholds: - Logos/avatars: 500KB (properly cropped are ~50-150KB) - Banners: 1.5MB (properly cropped are ~200-500KB) - Add comprehensive tests for migration logic When users refresh the page, the migration runs automatically and clears any oversized images, requiring them to re-upload using the new cropping flow. Co-Authored-By: hariom@cal.com <hariombalhara@gmail.com> * fixes * chore: remove migration test file Co-Authored-By: hariom@cal.com <hariombalhara@gmail.com> --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
1 parent 7840cc3 commit 19e89df

1 file changed

Lines changed: 52 additions & 2 deletions

File tree

apps/web/modules/onboarding/store/onboarding-store.ts

Lines changed: 52 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,23 @@
1+
import type { PersistOptions } from "zustand/middleware";
12
import { create } from "zustand";
23
import { persist } from "zustand/middleware";
34

45
import { onboardingIndexedDBStorage } from "./onboarding-storage";
56

7+
// Thresholds for detecting oversized images (in characters of base64 string)
8+
// Images larger than these were uploaded before the cropping fix and should be cleared
9+
const LOGO_SIZE_THRESHOLD = 500_000; // ~500KB - properly cropped logos are ~50-150KB
10+
const BANNER_SIZE_THRESHOLD = 1_500_000; // ~1.5MB - properly cropped banners are ~200-500KB
11+
12+
/**
13+
* Checks if a base64 image string exceeds the given threshold.
14+
* Returns true if the image should be cleared (is oversized).
15+
*/
16+
function isOversizedImage(imageData: string | null, threshold: number): boolean {
17+
if (!imageData) return false;
18+
return imageData.length > threshold;
19+
}
20+
621
export type PlanType = "personal" | "team" | "organization";
722
export type InviteRole = "MEMBER" | "ADMIN";
823

@@ -189,7 +204,42 @@ export const useOnboardingStore = create<OnboardingState>()(
189204
{
190205
name: "cal-onboarding-storage", // Storage key
191206
storage: onboardingIndexedDBStorage, // Use IndexedDB instead of localStorage for larger capacity
192-
// Optional: Only persist certain fields
207+
// Version 0: Had issue with Image sizes being too large.
208+
// Version 1: We fixed that and also migrated to version-1 to facilitate one-time cleanup of all oversized images.
209+
version: 1,
210+
migrate: (persistedState, version) => {
211+
if (version >= 1) {
212+
return persistedState as OnboardingState;
213+
}
214+
const state = persistedState as OnboardingState;
215+
216+
// Migration from version 0 (no version) to version 1:
217+
// Clear oversized images that were uploaded before the cropping fix (PR #27285)
218+
// These large images cause 429 errors when sent to the server
219+
if (state.organizationBrand) {
220+
if (isOversizedImage(state.organizationBrand.logo, LOGO_SIZE_THRESHOLD)) {
221+
state.organizationBrand.logo = null;
222+
}
223+
if (isOversizedImage(state.organizationBrand.banner, BANNER_SIZE_THRESHOLD)) {
224+
state.organizationBrand.banner = null;
225+
}
226+
}
227+
228+
if (state.teamBrand) {
229+
if (isOversizedImage(state.teamBrand.logo, LOGO_SIZE_THRESHOLD)) {
230+
state.teamBrand.logo = null;
231+
}
232+
}
233+
234+
if (state.personalDetails) {
235+
if (isOversizedImage(state.personalDetails.avatar, LOGO_SIZE_THRESHOLD)) {
236+
state.personalDetails.avatar = null;
237+
}
238+
}
239+
240+
return state;
241+
},
242+
// Only persist certain fields
193243
partialize: (state) => ({
194244
selectedPlan: state.selectedPlan,
195245
organizationDetails: state.organizationDetails,
@@ -204,6 +254,6 @@ export const useOnboardingStore = create<OnboardingState>()(
204254
teamId: state.teamId,
205255
personalDetails: state.personalDetails,
206256
}),
207-
}
257+
} as PersistOptions<OnboardingState, Partial<OnboardingState>>
208258
)
209259
);

0 commit comments

Comments
 (0)