Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(Meetings): add quick settings for midweek and weekend meetings #2403

Merged
merged 7 commits into from
Aug 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 36 additions & 15 deletions src/features/about/index.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,23 @@
import { Box, IconButton } from '@mui/material';
import { Box } from '@mui/material';
import { IconClose, IconInfo, IconLogo, IconRestart } from '@icons/index';
import { useAppTranslation } from '@hooks/index';
import { AboutProps } from './index.types';
import useAbout from './useAbout';
import Button from '@components/button';
import Dialog from '@components/dialog';
import IconButton from '@components/icon_button';
import TextMarkup from '@components/text_markup';
import Typography from '@components/typography';
import { IconClose, IconInfo, IconLogo } from '@icons/index';
import { useAppTranslation } from '@hooks/index';
import useAbout from './useAbout';

const About = () => {
const { currentYear, handleClose, isOpen, handleOpenDoc, handleOpenSupport } =
useAbout();
const About = (props: AboutProps) => {
const {
currentYear,
handleClose,
isOpen,
handleOpenDoc,
handleOpenSupport,
handleForceReload,
} = useAbout(props);

const { t } = useAppTranslation();

Expand Down Expand Up @@ -47,18 +55,31 @@ const About = () => {
<Box
sx={{
display: 'flex',
padding: 'var(--radius-none)',
alignItems: 'center',
gap: '16px',
justifyContent: 'space-between',
width: '100%',
}}
>
<IconLogo width={40} height={40} />
<Box>
<Typography className="h3">Organized</Typography>
<Typography className="body-regular" color="var(--grey-350)">
{import.meta.env.PACKAGE_VERSION}
</Typography>
<Box
sx={{
display: 'flex',
padding: 'var(--radius-none)',
alignItems: 'center',
gap: '16px',
}}
>
<IconLogo width={40} height={40} />
<Box>
<Typography className="h3">Organized</Typography>
<Typography className="body-regular" color="var(--grey-350)">
{import.meta.env.PACKAGE_VERSION}
</Typography>
</Box>
</Box>

<IconButton onClick={handleForceReload}>
<IconRestart color="var(--black)" />
</IconButton>
</Box>

<TextMarkup content={t('tr_appAboutDesc')} className="body-regular" />
Expand Down
3 changes: 3 additions & 0 deletions src/features/about/index.types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export type AboutProps = {
updatePwa: VoidFunction;
};
24 changes: 22 additions & 2 deletions src/features/about/useAbout.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,25 @@
import { useRecoilValue } from 'recoil';
import { isAboutOpenState } from '@states/app';
import { setIsAboutOpen, setIsSupportOpen } from '@services/recoil/app';
import { AboutProps } from './index.types';

const currentYear = new Date().getFullYear();

const useAbout = () => {
const useAbout = ({ updatePwa }: AboutProps) => {
const isOpen = useRecoilValue(isAboutOpenState);

const handleForceReload = () => {
try {
updatePwa();

setTimeout(() => {
window.location.reload();
}, 2000);
} catch (error) {
console.error(error.message);
}
};

const handleClose = async () => {
await setIsAboutOpen(false);
};
Expand All @@ -20,7 +33,14 @@ const useAbout = () => {
window.open(`https://guide.organized-app.com`, '_blank');
};

return { isOpen, handleClose, currentYear, handleOpenDoc, handleOpenSupport };
return {
isOpen,
handleClose,
currentYear,
handleOpenDoc,
handleOpenSupport,
handleForceReload,
};
};

export default useAbout;
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { useAppTranslation } from '@hooks/index';
import useCongregationPrivacy from './useCongregationPrivacy';
import AccessCodeView from './access_code_view';
import MasterKeyView from './master_key_view';
import OutgoingTalkAccess from './outgoing_talk_access';
import SwitchWithLabel from '@components/switch_with_label';

const CongregationPrivacy = () => {
Expand All @@ -15,8 +16,6 @@ const CongregationPrivacy = () => {
const {
timeAwayPublic,
handleTimeAwayPublicToggle,
outgoingTalksPublic,
handleOutgoingTalksPublicToggle,
isUserAdmin,
isConnected,
} = useCongregationPrivacy();
Expand All @@ -34,12 +33,8 @@ const CongregationPrivacy = () => {
checked={timeAwayPublic}
onChange={handleTimeAwayPublicToggle}
/>
<SwitchWithLabel
label={t('tr_showOutgoingToAll')}
helper={t('tr_showOutgoingToAllDesc')}
checked={outgoingTalksPublic}
onChange={handleOutgoingTalksPublicToggle}
/>

<OutgoingTalkAccess />
</CardSectionContent>

{isConnected && isUserAdmin && (
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { useAppTranslation } from '@hooks/index';
import useCongregationPrivacy from './useOutgoingTalkAccess';
import SwitchWithLabel from '@components/switch_with_label';

const OutgoingTalkAccess = () => {
const { t } = useAppTranslation();

const { outgoingTalksPublic, handleOutgoingTalksPublicToggle } =
useCongregationPrivacy();

return (
<SwitchWithLabel
label={t('tr_showOutgoingToAll')}
helper={t('tr_showOutgoingToAllDesc')}
checked={outgoingTalksPublic}
onChange={handleOutgoingTalksPublicToggle}
/>
);
};

export default OutgoingTalkAccess;
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { useEffect, useState } from 'react';
import { useRecoilValue } from 'recoil';
import { settingsState, userDataViewState } from '@states/settings';
import { dbAppSettingsUpdate } from '@services/dexie/settings';

const useOutgoingTalkAccess = () => {
const settings = useRecoilValue(settingsState);
const dataView = useRecoilValue(userDataViewState);

const [outgoingTalksPublic, setOutgoingTalksPublic] = useState(false);

const handleOutgoingTalksPublicToggle = async () => {
const weekendSettings = structuredClone(
settings.cong_settings.weekend_meeting
);

const current = weekendSettings.find((record) => record.type === dataView);

current.outgoing_talks_schedule_public.value = !outgoingTalksPublic;
current.outgoing_talks_schedule_public.updatedAt = new Date().toISOString();

await dbAppSettingsUpdate({
'cong_settings.weekend_meeting': weekendSettings,
});
};
Comment on lines +12 to +25
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add error handling for the async function.

The handleOutgoingTalksPublicToggle function should handle potential errors from the async operation to ensure robustness.

 const handleOutgoingTalksPublicToggle = async () => {
   try {
     const weekendSettings = structuredClone(
       settings.cong_settings.weekend_meeting
     );

     const current = weekendSettings.find((record) => record.type === dataView);

     current.outgoing_talks_schedule_public.value = !outgoingTalksPublic;
     current.outgoing_talks_schedule_public.updatedAt = new Date().toISOString();

     await dbAppSettingsUpdate({
       'cong_settings.weekend_meeting': weekendSettings,
     });
   } catch (error) {
     console.error('Failed to update outgoing talks public setting:', error);
   }
 };
Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const handleOutgoingTalksPublicToggle = async () => {
const weekendSettings = structuredClone(
settings.cong_settings.weekend_meeting
);
const current = weekendSettings.find((record) => record.type === dataView);
current.outgoing_talks_schedule_public.value = !outgoingTalksPublic;
current.outgoing_talks_schedule_public.updatedAt = new Date().toISOString();
await dbAppSettingsUpdate({
'cong_settings.weekend_meeting': weekendSettings,
});
};
const handleOutgoingTalksPublicToggle = async () => {
try {
const weekendSettings = structuredClone(
settings.cong_settings.weekend_meeting
);
const current = weekendSettings.find((record) => record.type === dataView);
current.outgoing_talks_schedule_public.value = !outgoingTalksPublic;
current.outgoing_talks_schedule_public.updatedAt = new Date().toISOString();
await dbAppSettingsUpdate({
'cong_settings.weekend_meeting': weekendSettings,
});
} catch (error) {
console.error('Failed to update outgoing talks public setting:', error);
}
};

Consider adding a loading state.

Consider adding a loading state to provide feedback to the user during the async operation.

 const useOutgoingTalkAccess = () => {
   const settings = useRecoilValue(settingsState);
   const dataView = useRecoilValue(userDataViewState);

   const [outgoingTalksPublic, setOutgoingTalksPublic] = useState(false);
+  const [isLoading, setIsLoading] = useState(false);

   const handleOutgoingTalksPublicToggle = async () => {
+    setIsLoading(true);
     try {
       const weekendSettings = structuredClone(
         settings.cong_settings.weekend_meeting
       );

       const current = weekendSettings.find((record) => record.type === dataView);

       current.outgoing_talks_schedule_public.value = !outgoingTalksPublic;
       current.outgoing_talks_schedule_public.updatedAt = new Date().toISOString();

       await dbAppSettingsUpdate({
         'cong_settings.weekend_meeting': weekendSettings,
       });
     } catch (error) {
       console.error('Failed to update outgoing talks public setting:', error);
     } finally {
+      setIsLoading(false);
     }
   };

   useEffect(() => {
     const weekendSettings = settings.cong_settings.weekend_meeting.find(
       (record) => record.type === dataView
     );

     setOutgoingTalksPublic(
       weekendSettings.outgoing_talks_schedule_public.value
     );
   }, [settings, dataView]);

   return {
     outgoingTalksPublic,
+    isLoading,
     handleOutgoingTalksPublicToggle,
   };
 };
Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const handleOutgoingTalksPublicToggle = async () => {
const weekendSettings = structuredClone(
settings.cong_settings.weekend_meeting
);
const current = weekendSettings.find((record) => record.type === dataView);
current.outgoing_talks_schedule_public.value = !outgoingTalksPublic;
current.outgoing_talks_schedule_public.updatedAt = new Date().toISOString();
await dbAppSettingsUpdate({
'cong_settings.weekend_meeting': weekendSettings,
});
};
const useOutgoingTalkAccess = () => {
const settings = useRecoilValue(settingsState);
const dataView = useRecoilValue(userDataViewState);
const [outgoingTalksPublic, setOutgoingTalksPublic] = useState(false);
const [isLoading, setIsLoading] = useState(false);
const handleOutgoingTalksPublicToggle = async () => {
setIsLoading(true);
try {
const weekendSettings = structuredClone(
settings.cong_settings.weekend_meeting
);
const current = weekendSettings.find((record) => record.type === dataView);
current.outgoing_talks_schedule_public.value = !outgoingTalksPublic;
current.outgoing_talks_schedule_public.updatedAt = new Date().toISOString();
await dbAppSettingsUpdate({
'cong_settings.weekend_meeting': weekendSettings,
});
} catch (error) {
console.error('Failed to update outgoing talks public setting:', error);
} finally {
setIsLoading(false);
}
};
useEffect(() => {
const weekendSettings = settings.cong_settings.weekend_meeting.find(
(record) => record.type === dataView
);
setOutgoingTalksPublic(
weekendSettings.outgoing_talks_schedule_public.value
);
}, [settings, dataView]);
return {
outgoingTalksPublic,
isLoading,
handleOutgoingTalksPublicToggle,
};
};


useEffect(() => {
const weekendSettings = settings.cong_settings.weekend_meeting.find(
(record) => record.type === dataView
);

setOutgoingTalksPublic(
weekendSettings.outgoing_talks_schedule_public.value
);
}, [settings, dataView]);

return {
outgoingTalksPublic,
handleOutgoingTalksPublicToggle,
};
};

export default useOutgoingTalkAccess;
Original file line number Diff line number Diff line change
@@ -1,21 +1,15 @@
import { useEffect, useState } from 'react';
import { useRecoilValue } from 'recoil';
import {
adminRoleState,
settingsState,
userDataViewState,
} from '@states/settings';
import { adminRoleState, settingsState } from '@states/settings';
import { dbAppSettingsUpdate } from '@services/dexie/settings';
import { congAccountConnectedState } from '@states/app';

const useCongregationPrivacy = () => {
const settings = useRecoilValue(settingsState);
const dataView = useRecoilValue(userDataViewState);
const isUserAdmin = useRecoilValue(adminRoleState);
const isConnected = useRecoilValue(congAccountConnectedState);

const [timeAwayPublic, setTimeAwayPublic] = useState(false);
const [outgoingTalksPublic, setOutgoingTalksPublic] = useState(false);

const handleTimeAwayPublicToggle = async () => {
const timeAway = structuredClone(settings.cong_settings.time_away_public);
Expand All @@ -28,38 +22,13 @@ const useCongregationPrivacy = () => {
});
};

const handleOutgoingTalksPublicToggle = async () => {
const weekendSettings = structuredClone(
settings.cong_settings.weekend_meeting
);

const current = weekendSettings.find((record) => record.type === dataView);

current.outgoing_talks_schedule_public.value = !outgoingTalksPublic;
current.outgoing_talks_schedule_public.updatedAt = new Date().toISOString();

await dbAppSettingsUpdate({
'cong_settings.weekend_meeting': weekendSettings,
});
};

useEffect(() => {
setTimeAwayPublic(settings.cong_settings.time_away_public.value);

const weekendSettings = settings.cong_settings.weekend_meeting.find(
(record) => record.type === dataView
);

setOutgoingTalksPublic(
weekendSettings.outgoing_talks_schedule_public.value
);
}, [settings, dataView]);
}, [settings]);

return {
timeAwayPublic,
outgoingTalksPublic,
handleTimeAwayPublicToggle,
handleOutgoingTalksPublicToggle,
isUserAdmin,
isConnected,
};
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { useAppTranslation } from '@hooks/index';
import useDisplayName from './useDisplayName';
import SwitchWithLabel from '@components/switch_with_label';

const DisplayName = () => {
const { t } = useAppTranslation();

const { displayNameMeeting, handleDisplayNameMeetingToggle } =
useDisplayName();

return (
<SwitchWithLabel
label={t('tr_useDisplayNameMeeting')}
checked={displayNameMeeting}
onChange={handleDisplayNameMeetingToggle}
/>
);
};

export default DisplayName;
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { useEffect, useState } from 'react';
import { useRecoilValue } from 'recoil';
import { settingsState, userDataViewState } from '@states/settings';
import { dbAppSettingsUpdate } from '@services/dexie/settings';

const useMeetingForms = () => {
const settings = useRecoilValue(settingsState);
const dataView = useRecoilValue(userDataViewState);

const [displayNameMeeting, setDisplayNameMeeting] = useState(false);

const handleDisplayNameMeetingToggle = async () => {
const displayNameEnabled = structuredClone(
settings.cong_settings.display_name_enabled.meetings
);

displayNameEnabled.value = !displayNameMeeting;
displayNameEnabled.updatedAt = new Date().toISOString();

await dbAppSettingsUpdate({
'cong_settings.display_name_enabled.meetings': displayNameEnabled,
});
};
Comment on lines +12 to +23
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add error handling for the async function.

The handleDisplayNameMeetingToggle function should handle potential errors from the async operation to ensure robustness.

 const handleDisplayNameMeetingToggle = async () => {
   try {
     const displayNameEnabled = structuredClone(
       settings.cong_settings.display_name_enabled.meetings
     );

     displayNameEnabled.value = !displayNameMeeting;
     displayNameEnabled.updatedAt = new Date().toISOString();

     await dbAppSettingsUpdate({
       'cong_settings.display_name_enabled.meetings': displayNameEnabled,
     });
   } catch (error) {
     console.error('Failed to update display name setting:', error);
   }
 };
Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const handleDisplayNameMeetingToggle = async () => {
const displayNameEnabled = structuredClone(
settings.cong_settings.display_name_enabled.meetings
);
displayNameEnabled.value = !displayNameMeeting;
displayNameEnabled.updatedAt = new Date().toISOString();
await dbAppSettingsUpdate({
'cong_settings.display_name_enabled.meetings': displayNameEnabled,
});
};
const handleDisplayNameMeetingToggle = async () => {
try {
const displayNameEnabled = structuredClone(
settings.cong_settings.display_name_enabled.meetings
);
displayNameEnabled.value = !displayNameMeeting;
displayNameEnabled.updatedAt = new Date().toISOString();
await dbAppSettingsUpdate({
'cong_settings.display_name_enabled.meetings': displayNameEnabled,
});
} catch (error) {
console.error('Failed to update display name setting:', error);
}
};

Consider adding a loading state.

Consider adding a loading state to provide feedback to the user during the async operation.

 const useMeetingForms = () => {
   const settings = useRecoilValue(settingsState);
   const dataView = useRecoilValue(userDataViewState);

   const [displayNameMeeting, setDisplayNameMeeting] = useState(false);
+  const [isLoading, setIsLoading] = useState(false);

   const handleDisplayNameMeetingToggle = async () => {
+    setIsLoading(true);
     try {
       const displayNameEnabled = structuredClone(
         settings.cong_settings.display_name_enabled.meetings
       );

       displayNameEnabled.value = !displayNameMeeting;
       displayNameEnabled.updatedAt = new Date().toISOString();

       await dbAppSettingsUpdate({
         'cong_settings.display_name_enabled.meetings': displayNameEnabled,
       });
     } catch (error) {
       console.error('Failed to update display name setting:', error);
     } finally {
+      setIsLoading(false);
     }
   };

   useEffect(() => {
     setDisplayNameMeeting(
       settings.cong_settings.display_name_enabled.meetings.value
     );
   }, [settings, dataView]);

   return {
     displayNameMeeting,
+    isLoading,
     handleDisplayNameMeetingToggle,
   };
 };
Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const handleDisplayNameMeetingToggle = async () => {
const displayNameEnabled = structuredClone(
settings.cong_settings.display_name_enabled.meetings
);
displayNameEnabled.value = !displayNameMeeting;
displayNameEnabled.updatedAt = new Date().toISOString();
await dbAppSettingsUpdate({
'cong_settings.display_name_enabled.meetings': displayNameEnabled,
});
};
const useMeetingForms = () => {
const settings = useRecoilValue(settingsState);
const dataView = useRecoilValue(userDataViewState);
const [displayNameMeeting, setDisplayNameMeeting] = useState(false);
const [isLoading, setIsLoading] = useState(false);
const handleDisplayNameMeetingToggle = async () => {
setIsLoading(true);
try {
const displayNameEnabled = structuredClone(
settings.cong_settings.display_name_enabled.meetings
);
displayNameEnabled.value = !displayNameMeeting;
displayNameEnabled.updatedAt = new Date().toISOString();
await dbAppSettingsUpdate({
'cong_settings.display_name_enabled.meetings': displayNameEnabled,
});
} catch (error) {
console.error('Failed to update display name setting:', error);
} finally {
setIsLoading(false);
}
};
useEffect(() => {
setDisplayNameMeeting(
settings.cong_settings.display_name_enabled.meetings.value
);
}, [settings, dataView]);
return {
displayNameMeeting,
isLoading,
handleDisplayNameMeetingToggle,
};
};


useEffect(() => {
setDisplayNameMeeting(
settings.cong_settings.display_name_enabled.meetings.value
);
}, [settings, dataView]);

return {
displayNameMeeting,
handleDisplayNameMeetingToggle,
};
};

export default useMeetingForms;
Loading
Loading