@churchapps/apphelper 0.5.11 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. package/dist/components/ErrorMessages.js +1 -1
  2. package/dist/components/ErrorMessages.js.map +1 -1
  3. package/dist/components/FormCardPayment.js +2 -2
  4. package/dist/components/FormCardPayment.js.map +1 -1
  5. package/dist/components/ImageEditor.d.ts.map +1 -1
  6. package/dist/components/ImageEditor.js +13 -8
  7. package/dist/components/ImageEditor.js.map +1 -1
  8. package/dist/components/PageHeader.js +1 -1
  9. package/dist/components/PageHeader.js.map +1 -1
  10. package/dist/components/QuestionEdit.js +2 -2
  11. package/dist/components/QuestionEdit.js.map +1 -1
  12. package/dist/components/SmallButton.js +1 -1
  13. package/dist/components/SmallButton.js.map +1 -1
  14. package/dist/components/gallery/GalleryModal.d.ts.map +1 -1
  15. package/dist/components/gallery/GalleryModal.js +2 -6
  16. package/dist/components/gallery/GalleryModal.js.map +1 -1
  17. package/dist/components/header/SecondaryMenu.js +2 -2
  18. package/dist/components/header/SecondaryMenu.js.map +1 -1
  19. package/dist/components/header/SiteHeader.d.ts.map +1 -1
  20. package/dist/components/header/SiteHeader.js +0 -3
  21. package/dist/components/header/SiteHeader.js.map +1 -1
  22. package/dist/components/notes/Note.js +1 -1
  23. package/dist/components/notes/Note.js.map +1 -1
  24. package/dist/components/wrapper/ChurchList.d.ts.map +1 -1
  25. package/dist/components/wrapper/ChurchList.js +0 -7
  26. package/dist/components/wrapper/ChurchList.js.map +1 -1
  27. package/dist/components/wrapper/NewPrivateMessage.d.ts.map +1 -1
  28. package/dist/components/wrapper/NewPrivateMessage.js +1 -2
  29. package/dist/components/wrapper/NewPrivateMessage.js.map +1 -1
  30. package/dist/components/wrapper/Notifications.js +1 -1
  31. package/dist/components/wrapper/Notifications.js.map +1 -1
  32. package/dist/components/wrapper/PrivateMessageDetails.d.ts.map +1 -1
  33. package/dist/components/wrapper/PrivateMessageDetails.js +0 -2
  34. package/dist/components/wrapper/PrivateMessageDetails.js.map +1 -1
  35. package/dist/components/wrapper/PrivateMessages.js +1 -1
  36. package/dist/components/wrapper/PrivateMessages.js.map +1 -1
  37. package/dist/components/wrapper/UserMenu.d.ts.map +1 -1
  38. package/dist/components/wrapper/UserMenu.js +0 -13
  39. package/dist/components/wrapper/UserMenu.js.map +1 -1
  40. package/dist/helpers/ErrorHelper.d.ts.map +1 -1
  41. package/dist/helpers/ErrorHelper.js +0 -2
  42. package/dist/helpers/ErrorHelper.js.map +1 -1
  43. package/dist/helpers/NotificationService.d.ts +0 -18
  44. package/dist/helpers/NotificationService.d.ts.map +1 -1
  45. package/dist/helpers/NotificationService.js +0 -65
  46. package/dist/helpers/NotificationService.js.map +1 -1
  47. package/dist/helpers/SocketHelper.d.ts.map +1 -1
  48. package/dist/helpers/SocketHelper.js +1 -53
  49. package/dist/helpers/SocketHelper.js.map +1 -1
  50. package/dist/helpers/UserHelper.d.ts.map +1 -1
  51. package/dist/helpers/UserHelper.js +0 -4
  52. package/dist/helpers/UserHelper.js.map +1 -1
  53. package/package.json +1 -1
  54. package/src/components/ErrorMessages.tsx +1 -1
  55. package/src/components/FormCardPayment.tsx +1 -1
  56. package/src/components/ImageEditor.tsx +167 -161
  57. package/src/components/PageHeader.tsx +2 -2
  58. package/src/components/QuestionEdit.tsx +2 -2
  59. package/src/components/SmallButton.tsx +1 -1
  60. package/src/components/gallery/GalleryModal.tsx +169 -173
  61. package/src/components/header/SecondaryMenu.tsx +2 -2
  62. package/src/components/header/SiteHeader.tsx +204 -207
  63. package/src/components/notes/Note.tsx +2 -2
  64. package/src/components/wrapper/ChurchList.tsx +145 -154
  65. package/src/components/wrapper/NewPrivateMessage.tsx +1 -2
  66. package/src/components/wrapper/Notifications.tsx +1 -1
  67. package/src/components/wrapper/PrivateMessageDetails.tsx +2 -6
  68. package/src/components/wrapper/PrivateMessages.tsx +1 -1
  69. package/src/components/wrapper/UserMenu.tsx +3 -17
  70. package/src/helpers/ErrorHelper.ts +41 -43
  71. package/src/helpers/NotificationService.ts +232 -296
  72. package/src/helpers/SocketHelper.ts +247 -296
  73. package/src/helpers/UserHelper.ts +2 -6
@@ -1,207 +1,204 @@
1
- import React from "react";
2
- import { AppBar, Link, styled, Toolbar } from "@mui/material";
3
- import { UserMenu } from "../wrapper/UserMenu";
4
- import { PersonHelper } from "../../helpers/PersonHelper";
5
- import { PrimaryMenu } from "./PrimaryMenu";
6
- import { SecondaryMenu } from "./SecondaryMenu";
7
- import { SecondaryMenuAlt } from "./SecondaryMenuAlt";
8
- import { SupportDrawer } from "./SupportDrawer";
9
- import { UserContextInterface } from "@churchapps/helpers";
10
- import { NotificationService } from "../../helpers/NotificationService";
11
-
12
- type Props = {
13
- primaryMenuLabel: string;
14
- primaryMenuItems:{ url: string, icon:string, label: string }[];
15
- secondaryMenuLabel: string;
16
- secondaryMenuItems:{ url: string, label: string }[];
17
- context: UserContextInterface;
18
- appName: string;
19
- onNavigate: (url: string) => void;
20
- }
21
-
22
- export const SiteHeader = React.memo((props:Props) => {
23
- // Initialize NotificationService without subscribing to count changes to prevent re-renders
24
- React.useEffect(() => {
25
- const initializeNotifications = async () => {
26
- if (props.context?.person?.id && props.context?.userChurch?.church?.id) {
27
- const service = NotificationService.getInstance();
28
- await service.initialize(props.context);
29
- }
30
- };
31
-
32
- initializeNotifications();
33
- }, [props.context?.person?.id, props.context?.userChurch?.church?.id]);
34
-
35
- const refresh = React.useCallback(async () => {
36
- // Direct access to NotificationService for refresh functionality
37
- await NotificationService.getInstance().refresh();
38
- }, []);
39
-
40
- // Memoize userName to prevent recreation
41
- const userName = React.useMemo(() => {
42
- if (props.context?.user) {
43
- return `${props.context.user.firstName} ${props.context.user.lastName}`;
44
- }
45
- return '';
46
- }, [props.context?.user?.firstName, props.context?.user?.lastName]);
47
-
48
- // Memoize profilePicture URL
49
- const profilePicture = React.useMemo(() => {
50
- return PersonHelper.getPhotoUrl(props.context?.person);
51
- }, [props.context?.person]);
52
-
53
- // Create a stable context object to prevent UserMenu recreation
54
- const stableContext = React.useMemo(() => {
55
- console.log('SiteHeader - Creating stableContext');
56
- console.log('SiteHeader - props.context:', props.context);
57
- console.log('SiteHeader - props.context.userChurches:', props.context?.userChurches);
58
-
59
- if (!props.context) return undefined;
60
-
61
- return {
62
- user: props.context.user,
63
- person: props.context.person,
64
- userChurch: props.context.userChurch,
65
- userChurches: props.context.userChurches,
66
- setUser: props.context.setUser,
67
- setPerson: props.context.setPerson,
68
- setUserChurch: props.context.setUserChurch,
69
- setUserChurches: props.context.setUserChurches
70
- };
71
- }, [
72
- props.context?.user?.id,
73
- props.context?.user?.firstName,
74
- props.context?.user?.lastName,
75
- props.context?.person?.id,
76
- props.context?.userChurch?.church?.id,
77
- props.context?.userChurches,
78
- props.context?.setUser,
79
- props.context?.setPerson,
80
- props.context?.setUserChurch,
81
- props.context?.setUserChurches
82
- ]);
83
-
84
- const CustomAppBar = styled(AppBar)(
85
- ({ theme }) => ({
86
- zIndex: theme.zIndex.drawer + 1,
87
- backgroundColor: "var(--c1, #1565C0)",
88
- transition: theme.transitions.create(["width", "margin"], {
89
- easing: theme.transitions.easing.sharp,
90
- duration: theme.transitions.duration.leavingScreen
91
- }),
92
- "& .MuiIcon-root": { color: "#FFFFFF" }
93
- })
94
- );
95
-
96
- const getRelatedArticles = () => {
97
- let result: any [] = [];
98
- if (props.appName === "B1Admin") {
99
- if (props.primaryMenuLabel === "People") {
100
- if (props.secondaryMenuLabel === "People") result = ["b1admin/adding-people", "b1admin/advanced-search", "b1admin/assigning-roles"];
101
- else if (props.secondaryMenuLabel === "Groups") result = ["b1admin/group-roster", "b1admin/groups", "b1admin/group-calendar"];
102
- else if (props.secondaryMenuLabel === "Attendance") result = ["b1admin/attendance", "b1admin/checkin"];
103
- }
104
- else if (props.primaryMenuLabel === "Donations") {
105
- if (props.secondaryMenuLabel === "Summary") result = ["b1admin/donation-report"];
106
- else if (props.secondaryMenuLabel === "Batches" || props.secondaryMenuLabel === "Funds") result = ["b1admin/giving", "b1admin/manual-input"];
107
- }
108
- else if (props.primaryMenuLabel === "Serving") {
109
- if (props.secondaryMenuLabel === "Plans") result = ["b1admin/plans"];
110
- else if (props.secondaryMenuLabel === "Tasks") result = ["b1admin/tasks", "b1admin/automations"];
111
- }
112
- else if (props.primaryMenuLabel === "Settings") {
113
- if (props.secondaryMenuLabel === "Settings") result = ["b1admin/assigning-roles", "b1admin/exporting-data", "b1admin/import-csv", "b1admin/import-from-breeze"];
114
- else if (props.secondaryMenuLabel === "Forms") result = ["b1admin/forms"];
115
- }
116
- } else if (props.appName === "B1") {
117
- if (props.primaryMenuLabel === "Mobile App") result = ["b1/admin/portal", "b1/mobile/setup"];
118
- else if (props.primaryMenuLabel === "Website") result = ["b1/admin/portal", "b1/admin/website-elements", "b1/admin/website-setup"];
119
- else if (props.primaryMenuLabel === "Sermons") result = ["b1/admin/sermons", "b1/admin/stream-setup"];
120
- else if (props.primaryMenuLabel === "Calendars") result = ["b1/portal/calendars"];
121
- }
122
- return result;
123
- }
124
-
125
- /*<Typography variant="h6" noWrap>{UserHelper.currentUserChurch?.church?.name || ""}</Typography>*/
126
- return (<>
127
- <div id="site-header" style={{
128
- '--c1': '#1565C0',
129
- '--c1d1': '#1358AD',
130
- '--c1d2': '#114A99',
131
- '--c1l2': '#568BDA',
132
- backgroundColor:"var(--c1)",
133
- color: "#FFF"
134
- } as React.CSSProperties}>
135
- <CustomAppBar id="site-app-bar" position="absolute">
136
- <Toolbar id="site-toolbar" sx={{ pr: "24px", backgroundColor: "var(--c1)", minHeight: "64px !important" }}>
137
- <PrimaryMenu label={props.primaryMenuLabel} menuItems={props.primaryMenuItems} onNavigate={props.onNavigate} />
138
- <SecondaryMenu label={props.secondaryMenuLabel} menuItems={props.secondaryMenuItems} onNavigate={props.onNavigate} />
139
- <div id="secondary-menu-container" style={{ flex: 1 }}>
140
- <SecondaryMenuAlt label={props.secondaryMenuLabel} menuItems={props.secondaryMenuItems} onNavigate={props.onNavigate} />
141
- </div>
142
- {props.context?.user?.id && (
143
- <UserMenu
144
- key="user-menu-stable"
145
- profilePicture={profilePicture}
146
- userName={userName}
147
- context={stableContext}
148
- appName={props.appName}
149
- loadCounts={refresh}
150
- notificationCounts={{notificationCount: 0, pmCount: 0}}
151
- onNavigate={props.onNavigate}
152
- />
153
- )}
154
- {!props.context?.user?.id && <Link id="login-link" href="/login" color="inherit" style={{ textDecoration: "none" }}>Login</Link>}
155
- <SupportDrawer appName={props.appName} relatedArticles={getRelatedArticles()} />
156
- </Toolbar>
157
- </CustomAppBar>
158
- <div id="app-bar-spacer" style={{ height: '64px' }}></div>
159
- </div>
160
- </>
161
- );
162
- }, (prevProps, nextProps) => {
163
- // Custom comparison to prevent unnecessary re-renders
164
-
165
- // Check if essential props have changed
166
- if (prevProps.primaryMenuLabel !== nextProps.primaryMenuLabel ||
167
- prevProps.secondaryMenuLabel !== nextProps.secondaryMenuLabel ||
168
- prevProps.appName !== nextProps.appName) {
169
- return false;
170
- }
171
-
172
- // Check if menu items arrays have changed (shallow comparison)
173
- if (prevProps.primaryMenuItems?.length !== nextProps.primaryMenuItems?.length ||
174
- prevProps.secondaryMenuItems?.length !== nextProps.secondaryMenuItems?.length) {
175
- return false;
176
- }
177
-
178
- // Check if user context has actually changed (deep comparison of essential parts)
179
- const prevUser = prevProps.context?.user;
180
- const nextUser = nextProps.context?.user;
181
-
182
- if (prevUser?.id !== nextUser?.id ||
183
- prevUser?.firstName !== nextUser?.firstName ||
184
- prevUser?.lastName !== nextUser?.lastName) {
185
- return false;
186
- }
187
-
188
- // Check if person context has changed
189
- if (prevProps.context?.person?.id !== nextProps.context?.person?.id) {
190
- return false;
191
- }
192
-
193
- // Check if church context has changed
194
- if (prevProps.context?.userChurch?.church?.id !== nextProps.context?.userChurch?.church?.id) {
195
- return false;
196
- }
197
-
198
- // Check if onNavigate function reference has changed
199
- if (prevProps.onNavigate !== nextProps.onNavigate) {
200
- return false;
201
- }
202
-
203
- // All essential props are the same, skip re-render
204
- return true;
205
- });
206
-
207
- SiteHeader.displayName = 'SiteHeader';
1
+ import React from "react";
2
+ import { AppBar, Link, styled, Toolbar } from "@mui/material";
3
+ import { UserMenu } from "../wrapper/UserMenu";
4
+ import { PersonHelper } from "../../helpers/PersonHelper";
5
+ import { PrimaryMenu } from "./PrimaryMenu";
6
+ import { SecondaryMenu } from "./SecondaryMenu";
7
+ import { SecondaryMenuAlt } from "./SecondaryMenuAlt";
8
+ import { SupportDrawer } from "./SupportDrawer";
9
+ import { UserContextInterface } from "@churchapps/helpers";
10
+ import { NotificationService } from "../../helpers/NotificationService";
11
+
12
+ type Props = {
13
+ primaryMenuLabel: string;
14
+ primaryMenuItems:{ url: string, icon:string, label: string }[];
15
+ secondaryMenuLabel: string;
16
+ secondaryMenuItems:{ url: string, label: string }[];
17
+ context: UserContextInterface;
18
+ appName: string;
19
+ onNavigate: (url: string) => void;
20
+ }
21
+
22
+ export const SiteHeader = React.memo((props:Props) => {
23
+ // Initialize NotificationService without subscribing to count changes to prevent re-renders
24
+ React.useEffect(() => {
25
+ const initializeNotifications = async () => {
26
+ if (props.context?.person?.id && props.context?.userChurch?.church?.id) {
27
+ const service = NotificationService.getInstance();
28
+ await service.initialize(props.context);
29
+ }
30
+ };
31
+
32
+ initializeNotifications();
33
+ }, [props.context?.person?.id, props.context?.userChurch?.church?.id]);
34
+
35
+ const refresh = React.useCallback(async () => {
36
+ // Direct access to NotificationService for refresh functionality
37
+ await NotificationService.getInstance().refresh();
38
+ }, []);
39
+
40
+ // Memoize userName to prevent recreation
41
+ const userName = React.useMemo(() => {
42
+ if (props.context?.user) {
43
+ return `${props.context.user.firstName} ${props.context.user.lastName}`;
44
+ }
45
+ return '';
46
+ }, [props.context?.user?.firstName, props.context?.user?.lastName]);
47
+
48
+ // Memoize profilePicture URL
49
+ const profilePicture = React.useMemo(() => {
50
+ return PersonHelper.getPhotoUrl(props.context?.person);
51
+ }, [props.context?.person]);
52
+
53
+ // Create a stable context object to prevent UserMenu recreation
54
+ const stableContext = React.useMemo(() => {
55
+
56
+ if (!props.context) return undefined;
57
+
58
+ return {
59
+ user: props.context.user,
60
+ person: props.context.person,
61
+ userChurch: props.context.userChurch,
62
+ userChurches: props.context.userChurches,
63
+ setUser: props.context.setUser,
64
+ setPerson: props.context.setPerson,
65
+ setUserChurch: props.context.setUserChurch,
66
+ setUserChurches: props.context.setUserChurches
67
+ };
68
+ }, [
69
+ props.context?.user?.id,
70
+ props.context?.user?.firstName,
71
+ props.context?.user?.lastName,
72
+ props.context?.person?.id,
73
+ props.context?.userChurch?.church?.id,
74
+ props.context?.userChurches,
75
+ props.context?.setUser,
76
+ props.context?.setPerson,
77
+ props.context?.setUserChurch,
78
+ props.context?.setUserChurches
79
+ ]);
80
+
81
+ const CustomAppBar = styled(AppBar)(
82
+ ({ theme }) => ({
83
+ zIndex: theme.zIndex.drawer + 1,
84
+ backgroundColor: "var(--c1, #1565C0)",
85
+ transition: theme.transitions.create(["width", "margin"], {
86
+ easing: theme.transitions.easing.sharp,
87
+ duration: theme.transitions.duration.leavingScreen
88
+ }),
89
+ "& .MuiIcon-root": { color: "#FFFFFF" }
90
+ })
91
+ );
92
+
93
+ const getRelatedArticles = () => {
94
+ let result: any [] = [];
95
+ if (props.appName === "B1Admin") {
96
+ if (props.primaryMenuLabel === "People") {
97
+ if (props.secondaryMenuLabel === "People") result = ["b1admin/adding-people", "b1admin/advanced-search", "b1admin/assigning-roles"];
98
+ else if (props.secondaryMenuLabel === "Groups") result = ["b1admin/group-roster", "b1admin/groups", "b1admin/group-calendar"];
99
+ else if (props.secondaryMenuLabel === "Attendance") result = ["b1admin/attendance", "b1admin/checkin"];
100
+ }
101
+ else if (props.primaryMenuLabel === "Donations") {
102
+ if (props.secondaryMenuLabel === "Summary") result = ["b1admin/donation-report"];
103
+ else if (props.secondaryMenuLabel === "Batches" || props.secondaryMenuLabel === "Funds") result = ["b1admin/giving", "b1admin/manual-input"];
104
+ }
105
+ else if (props.primaryMenuLabel === "Serving") {
106
+ if (props.secondaryMenuLabel === "Plans") result = ["b1admin/plans"];
107
+ else if (props.secondaryMenuLabel === "Tasks") result = ["b1admin/tasks", "b1admin/automations"];
108
+ }
109
+ else if (props.primaryMenuLabel === "Settings") {
110
+ if (props.secondaryMenuLabel === "Settings") result = ["b1admin/assigning-roles", "b1admin/exporting-data", "b1admin/import-csv", "b1admin/import-from-breeze"];
111
+ else if (props.secondaryMenuLabel === "Forms") result = ["b1admin/forms"];
112
+ }
113
+ } else if (props.appName === "B1") {
114
+ if (props.primaryMenuLabel === "Mobile App") result = ["b1/admin/portal", "b1/mobile/setup"];
115
+ else if (props.primaryMenuLabel === "Website") result = ["b1/admin/portal", "b1/admin/website-elements", "b1/admin/website-setup"];
116
+ else if (props.primaryMenuLabel === "Sermons") result = ["b1/admin/sermons", "b1/admin/stream-setup"];
117
+ else if (props.primaryMenuLabel === "Calendars") result = ["b1/portal/calendars"];
118
+ }
119
+ return result;
120
+ }
121
+
122
+ /*<Typography variant="h6" noWrap>{UserHelper.currentUserChurch?.church?.name || ""}</Typography>*/
123
+ return (<>
124
+ <div id="site-header" style={{
125
+ '--c1': '#1565C0',
126
+ '--c1d1': '#1358AD',
127
+ '--c1d2': '#114A99',
128
+ '--c1l2': '#568BDA',
129
+ backgroundColor:"var(--c1)",
130
+ color: "#FFF"
131
+ } as React.CSSProperties}>
132
+ <CustomAppBar id="site-app-bar" position="absolute">
133
+ <Toolbar id="site-toolbar" sx={{ pr: "24px", backgroundColor: "var(--c1)", minHeight: "64px !important" }}>
134
+ <PrimaryMenu label={props.primaryMenuLabel} menuItems={props.primaryMenuItems} onNavigate={props.onNavigate} />
135
+ <SecondaryMenu label={props.secondaryMenuLabel} menuItems={props.secondaryMenuItems} onNavigate={props.onNavigate} />
136
+ <div id="secondary-menu-container" style={{ flex: 1 }}>
137
+ <SecondaryMenuAlt label={props.secondaryMenuLabel} menuItems={props.secondaryMenuItems} onNavigate={props.onNavigate} />
138
+ </div>
139
+ {props.context?.user?.id && (
140
+ <UserMenu
141
+ key="user-menu-stable"
142
+ profilePicture={profilePicture}
143
+ userName={userName}
144
+ context={stableContext}
145
+ appName={props.appName}
146
+ loadCounts={refresh}
147
+ notificationCounts={{notificationCount: 0, pmCount: 0}}
148
+ onNavigate={props.onNavigate}
149
+ />
150
+ )}
151
+ {!props.context?.user?.id && <Link id="login-link" href="/login" color="inherit" style={{ textDecoration: "none" }}>Login</Link>}
152
+ <SupportDrawer appName={props.appName} relatedArticles={getRelatedArticles()} />
153
+ </Toolbar>
154
+ </CustomAppBar>
155
+ <div id="app-bar-spacer" style={{ height: '64px' }}></div>
156
+ </div>
157
+ </>
158
+ );
159
+ }, (prevProps, nextProps) => {
160
+ // Custom comparison to prevent unnecessary re-renders
161
+
162
+ // Check if essential props have changed
163
+ if (prevProps.primaryMenuLabel !== nextProps.primaryMenuLabel ||
164
+ prevProps.secondaryMenuLabel !== nextProps.secondaryMenuLabel ||
165
+ prevProps.appName !== nextProps.appName) {
166
+ return false;
167
+ }
168
+
169
+ // Check if menu items arrays have changed (shallow comparison)
170
+ if (prevProps.primaryMenuItems?.length !== nextProps.primaryMenuItems?.length ||
171
+ prevProps.secondaryMenuItems?.length !== nextProps.secondaryMenuItems?.length) {
172
+ return false;
173
+ }
174
+
175
+ // Check if user context has actually changed (deep comparison of essential parts)
176
+ const prevUser = prevProps.context?.user;
177
+ const nextUser = nextProps.context?.user;
178
+
179
+ if (prevUser?.id !== nextUser?.id ||
180
+ prevUser?.firstName !== nextUser?.firstName ||
181
+ prevUser?.lastName !== nextUser?.lastName) {
182
+ return false;
183
+ }
184
+
185
+ // Check if person context has changed
186
+ if (prevProps.context?.person?.id !== nextProps.context?.person?.id) {
187
+ return false;
188
+ }
189
+
190
+ // Check if church context has changed
191
+ if (prevProps.context?.userChurch?.church?.id !== nextProps.context?.userChurch?.church?.id) {
192
+ return false;
193
+ }
194
+
195
+ // Check if onNavigate function reference has changed
196
+ if (prevProps.onNavigate !== nextProps.onNavigate) {
197
+ return false;
198
+ }
199
+
200
+ // All essential props are the same, skip re-render
201
+ return true;
202
+ });
203
+
204
+ SiteHeader.displayName = 'SiteHeader';
@@ -59,11 +59,11 @@ export const Note: React.FC<Props> = (props) => {
59
59
  </Stack>
60
60
  <Box>
61
61
  {contents.map((c, i) => c ? (
62
- <Typography key={i} variant="body2" sx={{ mb: 0.5 }}>
62
+ <Typography key={`content-${i}-${c.substring(0, 20)}`} variant="body2" sx={{ mb: 0.5 }}>
63
63
  {c}
64
64
  </Typography>
65
65
  ) : (
66
- <Box key={i} sx={{ height: '1em' }} />
66
+ <Box key={`empty-${i}`} sx={{ height: '1em' }} />
67
67
  ))}
68
68
  </Box>
69
69
  </Box>