@churchapps/apphelper 0.4.18 → 0.4.20

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 (36) hide show
  1. package/dist/components/DisplayBox.js +1 -1
  2. package/dist/components/DisplayBox.js.map +1 -1
  3. package/dist/components/InputBox.js +1 -1
  4. package/dist/components/InputBox.js.map +1 -1
  5. package/dist/components/Loading.js +1 -1
  6. package/dist/components/Loading.js.map +1 -1
  7. package/dist/components/PageHeader.d.ts.map +1 -1
  8. package/dist/components/PageHeader.js +6 -6
  9. package/dist/components/PageHeader.js.map +1 -1
  10. package/dist/components/header/SiteHeader.d.ts.map +1 -1
  11. package/dist/components/header/SiteHeader.js +5 -2
  12. package/dist/components/header/SiteHeader.js.map +1 -1
  13. package/dist/components/wrapper/ChurchList.d.ts +1 -0
  14. package/dist/components/wrapper/ChurchList.d.ts.map +1 -1
  15. package/dist/components/wrapper/ChurchList.js +73 -13
  16. package/dist/components/wrapper/ChurchList.js.map +1 -1
  17. package/dist/components/wrapper/Notifications.d.ts.map +1 -1
  18. package/dist/components/wrapper/Notifications.js +4 -4
  19. package/dist/components/wrapper/Notifications.js.map +1 -1
  20. package/dist/components/wrapper/UserMenu.d.ts +1 -3
  21. package/dist/components/wrapper/UserMenu.d.ts.map +1 -1
  22. package/dist/components/wrapper/UserMenu.js +53 -9
  23. package/dist/components/wrapper/UserMenu.js.map +1 -1
  24. package/dist/helpers/UserHelper.d.ts.map +1 -1
  25. package/dist/helpers/UserHelper.js +24 -0
  26. package/dist/helpers/UserHelper.js.map +1 -1
  27. package/package.json +1 -1
  28. package/src/components/DisplayBox.tsx +8 -8
  29. package/src/components/InputBox.tsx +8 -8
  30. package/src/components/Loading.tsx +1 -1
  31. package/src/components/PageHeader.tsx +8 -4
  32. package/src/components/header/SiteHeader.tsx +10 -8
  33. package/src/components/wrapper/ChurchList.tsx +83 -13
  34. package/src/components/wrapper/Notifications.tsx +6 -5
  35. package/src/components/wrapper/UserMenu.tsx +70 -28
  36. package/src/helpers/UserHelper.ts +26 -0
@@ -88,7 +88,7 @@ export const Notifications: React.FC<Props> = (props) => {
88
88
  const getNotificationList = () => {
89
89
  if (notifications.length === 0) {
90
90
  return (
91
- <Box sx={{ textAlign: 'center', py: 4 }}>
91
+ <Box id="notifications-empty" sx={{ textAlign: 'center', py: 4 }}>
92
92
  <NotificationsIcon sx={{ fontSize: 48, color: 'grey.400', mb: 2 }} />
93
93
  <Typography variant="h6" color="textSecondary">
94
94
  No notifications
@@ -101,7 +101,7 @@ export const Notifications: React.FC<Props> = (props) => {
101
101
  }
102
102
 
103
103
  return (
104
- <List sx={{ width: '100%' }}>
104
+ <List id="notifications-list" sx={{ width: '100%' }}>
105
105
  {notifications.map((notification, index) => {
106
106
  let datePosted = new Date(notification.timeSent);
107
107
  const displayDuration = DateHelper.getDisplayDuration(datePosted);
@@ -110,6 +110,7 @@ export const Notifications: React.FC<Props> = (props) => {
110
110
  return (
111
111
  <React.Fragment key={notification.id}>
112
112
  <ListItem
113
+ id={`notification-item-${notification.id}`}
113
114
  component="button"
114
115
  onClick={() => handleClick(notification)}
115
116
  sx={{
@@ -194,14 +195,14 @@ export const Notifications: React.FC<Props> = (props) => {
194
195
 
195
196
 
196
197
  return (
197
- <Paper elevation={0} sx={{ height: '100%', display: 'flex', flexDirection: 'column' }}>
198
- <Box sx={{ p: 2, borderBottom: 1, borderColor: 'divider' }}>
198
+ <Paper id="notifications-panel" elevation={0} sx={{ height: '100%', display: 'flex', flexDirection: 'column' }}>
199
+ <Box id="notifications-header" sx={{ p: 2, borderBottom: 1, borderColor: 'divider' }}>
199
200
  <Typography variant="h6" component="h2">
200
201
  Notifications
201
202
  </Typography>
202
203
  </Box>
203
204
 
204
- <Box sx={{ flex: 1, overflow: 'auto' }}>
205
+ <Box id="notifications-content" sx={{ flex: 1, overflow: 'auto' }}>
205
206
  {isLoading ? (
206
207
  <Box sx={{ p: 2 }}>
207
208
  {[...Array(3)].map((_, index) => (
@@ -19,8 +19,6 @@ interface Props {
19
19
  loadCounts: () => void;
20
20
  userName: string;
21
21
  profilePicture: string;
22
- userChurches: LoginUserChurchInterface[];
23
- currentUserChurch: LoginUserChurchInterface;
24
22
  context: UserContextInterface;
25
23
  appName: string;
26
24
  onNavigate: (url: string) => void;
@@ -98,8 +96,10 @@ const UserMenuContent: React.FC<Props> = React.memo((props) => {
98
96
  };
99
97
 
100
98
  const handleSwitchChurch = () => {
99
+ console.log('UserMenu - handleSwitchChurch called');
101
100
  removeCookie("lastChurchId", { path: "/" });
102
101
  setTabIndex(2);
102
+ console.log('UserMenu - tabIndex set to 2');
103
103
  };
104
104
 
105
105
  const getMainLinks = () => {
@@ -151,24 +151,64 @@ const UserMenuContent: React.FC<Props> = React.memo((props) => {
151
151
 
152
152
  const [tabIndex, setTabIndex] = React.useState(0);
153
153
 
154
- const getTabs = () => (
155
- <Box sx={{ borderBottom: 1, borderColor: "divider" }}>
156
- <TabPanel value={tabIndex} index={0}>
157
- {getMainLinks()}
158
- </TabPanel>
159
- <TabPanel value={tabIndex} index={1}>
160
- <NavItem label="Back" key="AppBack" icon="arrow_back" onClick={() => { setTabIndex(0); }} />
161
- <AppList currentUserChurch={props.currentUserChurch} appName={props.appName} onNavigate={props.onNavigate} />
162
- </TabPanel>
163
- <TabPanel value={tabIndex} index={2}>
164
- <div style={{ maxHeight: '70vh', overflowY: "auto" }}>
165
- <NavItem label="Back" key="ChurchBack" icon="arrow_back" onClick={() => { setTabIndex(0); }} />
166
- <ChurchList userChurches={props.userChurches} currentUserChurch={props.currentUserChurch} context={props.context} onDelete={handleClose} />
167
- </div>
168
- </TabPanel>
169
-
170
- </Box>
171
- );
154
+ const getTabs = () => {
155
+ console.log('UserMenu getTabs - Current tabIndex:', tabIndex);
156
+ return (
157
+ <Box sx={{ borderBottom: 1, borderColor: "divider" }}>
158
+ <TabPanel value={tabIndex} index={0}>
159
+ {getMainLinks()}
160
+ </TabPanel>
161
+ <TabPanel value={tabIndex} index={1}>
162
+ <NavItem label="Back" key="AppBack" icon="arrow_back" onClick={() => { setTabIndex(0); }} />
163
+ <AppList currentUserChurch={props.context?.userChurch} appName={props.appName} onNavigate={props.onNavigate} />
164
+ </TabPanel>
165
+ <TabPanel value={tabIndex} index={2}>
166
+ <div style={{ maxHeight: '70vh', overflowY: "auto" }}>
167
+ <NavItem label="Back" key="ChurchBack" icon="arrow_back" onClick={() => { setTabIndex(0); }} />
168
+ {(() => {
169
+ console.log('UserMenu Church Tab - Rendering church list section');
170
+ console.log('UserMenu Church Tab - Full context:', props.context);
171
+ console.log('UserMenu Church Tab - context.userChurches:', props.context?.userChurches);
172
+ console.log('UserMenu Church Tab - context.userChurches[0]:', props.context?.userChurches?.[0]);
173
+ console.log('UserMenu Church Tab - context.userChurch:', props.context?.userChurch);
174
+ console.log('UserMenu Church Tab - userChurches type:', typeof props.context?.userChurches);
175
+ console.log('UserMenu Church Tab - userChurches is array?', Array.isArray(props.context?.userChurches));
176
+ console.log('UserMenu Church Tab - userChurches length:', props.context?.userChurches?.length);
177
+
178
+ // Check if userChurches is actually the userChurch object
179
+ if (props.context?.userChurches && !Array.isArray(props.context.userChurches) && (props.context.userChurches as any).id) {
180
+ console.error('UserMenu - ERROR: context.userChurches contains a single church object instead of an array!');
181
+ console.log('UserMenu - Attempting to use context.userChurch as single item array');
182
+ const churchArray = props.context.userChurch ? [props.context.userChurch] : [];
183
+ return <ChurchList userChurches={churchArray} currentUserChurch={props.context?.userChurch} context={props.context} onDelete={handleClose} onChurchChange={() => {
184
+ handleClose();
185
+ // Don't navigate - just close the menu and let the context update trigger re-renders
186
+ }} />;
187
+ }
188
+
189
+ if (!props.context?.userChurches) {
190
+ return <Typography sx={{ p: 2, color: 'text.secondary' }}>Loading churches...</Typography>;
191
+ } else if (!Array.isArray(props.context.userChurches)) {
192
+ return <Typography sx={{ p: 2, color: 'text.secondary', fontWeight: 'bold' }}>Error: Invalid church data format</Typography>;
193
+ } else if (props.context.userChurches.length === 0) {
194
+ return <Typography sx={{ p: 2, color: 'text.secondary' }}>No churches available</Typography>;
195
+ } else {
196
+ // Ensure we always pass an array
197
+ const churchesArray = Array.isArray(props.context.userChurches)
198
+ ? props.context.userChurches
199
+ : [props.context.userChurches];
200
+ console.log('UserMenu - Passing to ChurchList:', churchesArray);
201
+ return <ChurchList userChurches={churchesArray} currentUserChurch={props.context?.userChurch} context={props.context} onDelete={handleClose} onChurchChange={() => {
202
+ handleClose();
203
+ // Don't navigate - just close the menu and let the context update trigger re-renders
204
+ }} />;
205
+ }
206
+ })()}
207
+ </div>
208
+ </TabPanel>
209
+ </Box>
210
+ );
211
+ };
172
212
 
173
213
  const getModals = () => {
174
214
  // Helper function to get label with fallback
@@ -180,6 +220,7 @@ const UserMenuContent: React.FC<Props> = React.memo((props) => {
180
220
  return (
181
221
  <>
182
222
  <Dialog
223
+ id="private-messages-modal"
183
224
  open={showPM}
184
225
  onClose={() => {
185
226
  modalStateStore.setShowPM(false);
@@ -195,7 +236,7 @@ const UserMenuContent: React.FC<Props> = React.memo((props) => {
195
236
  }
196
237
  }}
197
238
  >
198
- <DialogTitle>{getLabel("wrapper.messages", "Messages")}</DialogTitle>
239
+ <DialogTitle id="private-messages-title">{getLabel("wrapper.messages", "Messages")}</DialogTitle>
199
240
  <DialogContent
200
241
  sx={{
201
242
  flex: 1,
@@ -211,6 +252,7 @@ const UserMenuContent: React.FC<Props> = React.memo((props) => {
211
252
  </Dialog>
212
253
 
213
254
  <Dialog
255
+ id="notifications-modal"
214
256
  open={showNotifications}
215
257
  onClose={() => {
216
258
  modalStateStore.setShowNotifications(false);
@@ -218,7 +260,7 @@ const UserMenuContent: React.FC<Props> = React.memo((props) => {
218
260
  maxWidth="md"
219
261
  fullWidth
220
262
  >
221
- <DialogTitle>{getLabel("wrapper.notifications", "Notifications")}</DialogTitle>
263
+ <DialogTitle id="notifications-title">{getLabel("wrapper.notifications", "Notifications")}</DialogTitle>
222
264
  <DialogContent>
223
265
  <Notifications context={props.context} appName={props.appName} onUpdate={props.loadCounts} onNavigate={props.onNavigate} />
224
266
  </DialogContent>
@@ -286,13 +328,13 @@ const UserMenuContent: React.FC<Props> = React.memo((props) => {
286
328
 
287
329
  return (
288
330
  <>
289
- <Button onClick={handleClick} color="inherit" aria-controls={open ? "account-menu" : undefined} aria-haspopup="true" aria-expanded={open ? "true" : undefined} style={{ textTransform: "none" }} endIcon={<Icon>expand_more</Icon>}>
290
- <Badge badgeContent={totalNotifcations} color="error" invisible={totalNotifcations===0}>
291
- <Avatar src={getProfilePic()} sx={{ width: 32, height: 32, marginRight: 1 }}></Avatar>
331
+ <Button id="user-menu-button" onClick={handleClick} color="inherit" aria-controls={open ? "account-menu" : undefined} aria-haspopup="true" aria-expanded={open ? "true" : undefined} style={{ textTransform: "none" }} endIcon={<Icon>expand_more</Icon>}>
332
+ <Badge id="user-menu-notification-badge" badgeContent={totalNotifcations} color="error" invisible={totalNotifcations===0}>
333
+ <Avatar id="user-menu-avatar" src={getProfilePic()} sx={{ width: 32, height: 32, marginRight: 1 }}></Avatar>
292
334
  </Badge>
293
335
  </Button>
294
336
 
295
- <Menu anchorEl={anchorEl} id="account-menu" open={open} onClose={handleClose} onClick={(e) => { handleItemClick(e) }} slotProps={{ paper: paperProps }} transformOrigin={{ horizontal: "right", vertical: "top" }} anchorOrigin={{ horizontal: "right", vertical: "bottom" }} sx={{ "& .MuiBox-root": { borderBottom: 0 } }}>
337
+ <Menu anchorEl={anchorEl} id="user-menu-dropdown" open={open} onClose={handleClose} onClick={(e) => { handleItemClick(e) }} slotProps={{ paper: paperProps }} transformOrigin={{ horizontal: "right", vertical: "top" }} anchorOrigin={{ horizontal: "right", vertical: "bottom" }} sx={{ "& .MuiBox-root": { borderBottom: 0 } }}>
296
338
  {getTabs()}
297
339
  </Menu>
298
340
  {getModals()}
@@ -326,8 +368,8 @@ export const UserMenu: React.FC<Props> = React.memo((props) => {
326
368
  return false;
327
369
  }
328
370
 
329
- // Check if userChurches array changed
330
- if (prevProps.userChurches?.length !== nextProps.userChurches?.length) {
371
+ // Check if userChurches array changed in context
372
+ if (prevProps.context?.userChurches?.length !== nextProps.context?.userChurches?.length) {
331
373
  return false;
332
374
  }
333
375
 
@@ -11,6 +11,19 @@ export class UserHelper {
11
11
  static selectChurch = async (context?: UserContextInterface, churchId?: string, keyName?: string) => {
12
12
  let userChurch = null;
13
13
 
14
+ // Ensure userChurches is initialized
15
+ if (!UserHelper.userChurches || !Array.isArray(UserHelper.userChurches)) {
16
+ console.error('UserHelper.userChurches is not initialized or not an array:', UserHelper.userChurches);
17
+ // Try to get userChurches from context if available
18
+ if (context?.userChurches && Array.isArray(context.userChurches)) {
19
+ console.log('Using userChurches from context');
20
+ UserHelper.userChurches = context.userChurches;
21
+ } else {
22
+ console.error('Cannot select church: no valid userChurches available');
23
+ return;
24
+ }
25
+ }
26
+
14
27
  if (churchId) {
15
28
  UserHelper.userChurches.forEach(uc => {
16
29
  if (uc.church.id === churchId) userChurch = uc;
@@ -25,7 +38,20 @@ export class UserHelper {
25
38
  // TODO - remove context code from here and perform the logic in the component itself.
26
39
  if (context) {
27
40
  if (context.userChurch !== null) UserHelper.churchChanged = true;
41
+ console.log('UserHelper.selectChurch - Setting userChurch in context:', userChurch);
28
42
  context.setUserChurch(UserHelper.currentUserChurch);
43
+
44
+ // Also ensure user is still set in context
45
+ if (UserHelper.user && context.setUser) {
46
+ console.log('UserHelper.selectChurch - Ensuring user is set in context:', UserHelper.user);
47
+ context.setUser(UserHelper.user);
48
+ }
49
+
50
+ // Update person if available
51
+ if (UserHelper.person && context.setPerson) {
52
+ console.log('UserHelper.selectChurch - Ensuring person is set in context:', UserHelper.person);
53
+ context.setPerson(UserHelper.person);
54
+ }
29
55
  }
30
56
  }
31
57
  }