Skip to content

Commit 7eab570

Browse files
authored
Merge pull request #2732 from daostack/CW-hotfix-firebase-firestore-settings
[Hotfix] Firebase settings
2 parents 8f5238c + fb785d2 commit 7eab570

File tree

3 files changed

+123
-40
lines changed

3 files changed

+123
-40
lines changed

src/shared/constants/featureFlags.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ export enum FeatureFlags {
33
AiBot = "AiBot",
44
AiBotPro = "AiBotPro",
55
UpdateRoles = "UpdateRoles",
6+
HavingAnIssue = "HavingAnIssue"
67
}
78

89
export enum FeatureFlagVisibility {

src/shared/layouts/SidenavLayout/components/SidenavContent/components/UserInfo/components/MenuItems/MenuItems.tsx

Lines changed: 54 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,22 @@
1-
import React, { FC } from "react";
1+
import React, { FC, useMemo } from "react";
22
import { useDispatch } from "react-redux";
33
import { useLocation } from "react-router";
44
import classNames from "classnames";
55
import { Menu } from "@headlessui/react";
66
import { logOut } from "@/pages/Auth/store/actions";
7+
import { FeatureFlags } from "@/shared/constants";
78
import { useRoutesContext } from "@/shared/contexts";
9+
import { useFeatureFlag } from "@/shared/hooks/useFeatureFlag";
810
import {
911
Avatar3Icon,
1012
BillingIcon,
1113
LogoutIcon,
1214
NotificationsIcon,
1315
} from "@/shared/icons";
16+
import ReportIcon from "@/shared/icons/report.icon";
1417
import ThemeIcon from "@/shared/icons/theme.icon";
1518
import { toggleTheme } from "@/shared/store/actions";
19+
import { clearFirestoreCache } from "@/shared/utils/firebase";
1620
import { MenuItem } from "./components";
1721
import { Item, ItemType } from "./types";
1822
import styles from "./MenuItems.module.scss";
@@ -43,6 +47,9 @@ const MenuItems: FC<MenuItemsProps> = (props) => {
4347
const { pathname } = useLocation();
4448
const isV04 = pathname.includes("-v04");
4549

50+
const featureFlags = useFeatureFlag();
51+
const isHavingAnIssueEnabled = featureFlags?.get(FeatureFlags.HavingAnIssue);
52+
4653
const toggleThemeMenuItem = {
4754
key: "theme",
4855
type: ItemType.Button,
@@ -53,36 +60,53 @@ const MenuItems: FC<MenuItemsProps> = (props) => {
5360
},
5461
};
5562

56-
const items: Item[] = [
57-
{
58-
key: "my-profile",
59-
text: "My profile",
60-
icon: <Avatar3Icon />,
61-
to: getProfilePagePath(),
62-
},
63-
{
64-
key: "settings",
65-
text: "Notifications",
66-
icon: <NotificationsIcon />,
67-
to: getSettingsPagePath(),
68-
},
69-
{
70-
key: "billing",
71-
text: "Billing",
72-
icon: <BillingIcon />,
73-
to: getBillingPagePath(),
74-
},
75-
...insertIf(!isV04, toggleThemeMenuItem),
76-
{
77-
key: "log-out",
78-
type: ItemType.Button,
79-
text: "Log out",
80-
icon: <LogoutIcon />,
81-
onClick: () => {
82-
dispatch(logOut());
63+
const items: Item[] = useMemo(() => {
64+
const menuItems = [
65+
{
66+
key: "my-profile",
67+
text: "My profile",
68+
icon: <Avatar3Icon />,
69+
type: ItemType.Button,
70+
to: getProfilePagePath(),
8371
},
84-
},
85-
];
72+
{
73+
key: "settings",
74+
text: "Notifications",
75+
icon: <NotificationsIcon />,
76+
to: getSettingsPagePath(),
77+
},
78+
{
79+
key: "billing",
80+
text: "Billing",
81+
icon: <BillingIcon />,
82+
to: getBillingPagePath(),
83+
},
84+
...insertIf(!isV04, toggleThemeMenuItem),
85+
{
86+
key: "log-out",
87+
type: ItemType.Button,
88+
text: "Log out",
89+
icon: <LogoutIcon />,
90+
onClick: () => {
91+
dispatch(logOut());
92+
},
93+
},
94+
];
95+
96+
if (isHavingAnIssueEnabled) {
97+
menuItems.push({
98+
key: "issue",
99+
text: "Having an issue?",
100+
icon: <ReportIcon />,
101+
type: ItemType.Button,
102+
onClick: () => {
103+
clearFirestoreCache();
104+
},
105+
});
106+
}
107+
108+
return menuItems;
109+
}, [isHavingAnIssueEnabled, isV04, toggleThemeMenuItem]);
86110

87111
return (
88112
<Menu.Items as={React.Fragment}>

src/shared/utils/firebase.tsx

Lines changed: 68 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,80 @@ import { local } from "@/config";
99
import { Environment, REACT_APP_ENV } from "@/shared/constants";
1010
import config from "../../config";
1111

12+
const CACHE_SIZE_LIMIT = 104857600; // 100 MB
13+
1214
interface FirebaseError extends Error {
1315
code: string;
1416
}
1517

1618
const app = firebase.initializeApp(config.firebase);
19+
let db = firebase.firestore();
20+
21+
enableUnlimitedCachePersistence();
22+
// Function to handle Firestore persistence errors
23+
function handlePersistenceError(err: any) {
24+
if (err.code === "failed-precondition") {
25+
console.log("Multiple tabs open or other conflict.");
26+
} else if (err.code === "unimplemented") {
27+
console.log("Persistence is not supported in this browser.");
28+
} else if (err.name === "QuotaExceededError") {
29+
console.log("Storage quota exceeded. Consider clearing cache.");
30+
clearFirestoreCache();
31+
} else {
32+
console.error("Error enabling persistence:", err);
33+
}
34+
}
35+
36+
function reinitializeFirestoreWithPersistence() {
37+
db = firebase.firestore(); // Reinitialize Firestore instance
38+
const settings = { cacheSizeBytes: CACHE_SIZE_LIMIT };
39+
db.settings(settings);
40+
41+
db.enablePersistence({ synchronizeTabs: true })
42+
.then(() => {
43+
console.log("Persistence re-enabled.");
44+
return;
45+
})
46+
.catch(handlePersistenceError);
47+
}
48+
49+
// Function to clear Firestore cache and re-enable persistence
50+
export function clearFirestoreCache() {
51+
db.terminate()
52+
.then(() => {
53+
console.log("Firestore instance terminated.");
54+
return db.clearPersistence(); // Safe to clear persistence now
55+
})
56+
.then(() => {
57+
console.log("Persistence cleared. Waiting before reinitializing...");
58+
return new Promise((resolve) => setTimeout(resolve, 2000)); // Wait 2 second
59+
})
60+
.then(() => {
61+
console.log("Cache cleared successfully.");
62+
reinitializeFirestoreWithPersistence(); // Reinitialize Firestore
63+
window.location.reload();
64+
return;
65+
})
66+
.catch((err) => {
67+
if (err.code === "failed-precondition") {
68+
console.log("Cannot clear persistence: Firestore is still running.");
69+
} else {
70+
console.error("Error clearing persistence cache:", err);
71+
}
72+
});
73+
}
74+
75+
// Enable Firestore persistence with unlimited cache size and error handling
76+
function enableUnlimitedCachePersistence() {
77+
const settings = {
78+
cacheSizeBytes: CACHE_SIZE_LIMIT,
79+
};
80+
db.settings(settings);
81+
82+
db.enablePersistence({ synchronizeTabs: true }).catch(handlePersistenceError);
83+
}
1784

85+
// Enable persistence in the local environment (with Firestore and Auth emulators)
1886
if (REACT_APP_ENV === Environment.Local) {
1987
firebase.auth().useEmulator(local.firebase.authDomain);
2088
firebase
@@ -23,16 +91,6 @@ if (REACT_APP_ENV === Environment.Local) {
2391
"localhost",
2492
Number(local.firebase.databaseURL.split(/:/g)[2]),
2593
);
26-
} else {
27-
firebase
28-
.firestore()
29-
.enablePersistence({
30-
synchronizeTabs: true,
31-
experimentalForceOwningTab: false,
32-
})
33-
.catch((error) => {
34-
console.error("Error enabling persistence", error);
35-
});
3694
}
3795

3896
let perf;

0 commit comments

Comments
 (0)