diff --git a/converter/svg/sources/name=backup-organized.svg b/converter/svg/sources/name=backup-organized.svg
new file mode 100644
index 0000000000..0353c8a1da
--- /dev/null
+++ b/converter/svg/sources/name=backup-organized.svg
@@ -0,0 +1,9 @@
+
diff --git a/converter/svg/sources/name=import-export.svg b/converter/svg/sources/name=import-export.svg
new file mode 100644
index 0000000000..1ec8069b42
--- /dev/null
+++ b/converter/svg/sources/name=import-export.svg
@@ -0,0 +1,8 @@
+
diff --git a/converter/svg/sources/name=import-json.svg b/converter/svg/sources/name=import-json.svg
new file mode 100644
index 0000000000..d4c3899ba7
--- /dev/null
+++ b/converter/svg/sources/name=import-json.svg
@@ -0,0 +1,8 @@
+
diff --git a/package-lock.json b/package-lock.json
index b084ef9f28..262f6f75af 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "organized",
- "version": "3.2.0",
+ "version": "3.3.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "organized",
- "version": "3.2.0",
+ "version": "3.3.0",
"license": "MIT",
"dependencies": {
"@emotion/react": "^11.13.3",
@@ -37,6 +37,7 @@
"qrcode": "^1.5.4",
"react": "^18.3.0",
"react-dom": "^18.3.1",
+ "react-dropzone": "^14.3.5",
"react-i18next": "^15.1.3",
"react-lottie-player": "^2.1.0",
"react-pdf-html": "^2.1.2",
@@ -7402,6 +7403,15 @@
"node": ">= 4.0.0"
}
},
+ "node_modules/attr-accept": {
+ "version": "2.2.5",
+ "resolved": "https://registry.npmjs.org/attr-accept/-/attr-accept-2.2.5.tgz",
+ "integrity": "sha512-0bDNnY/u6pPwHDMoF0FieU354oBi0a8rD9FcsLwzcGWbc8KS8KPIi7y+s13OlVY+gMWc/9xEMUgNE6Qm8ZllYQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=4"
+ }
+ },
"node_modules/available-typed-arrays": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz",
@@ -10695,6 +10705,18 @@
"resolved": "https://registry.npmjs.org/file-select-dialog/-/file-select-dialog-1.5.4.tgz",
"integrity": "sha512-KrutaoxLbYGx8WSBsKJEVysGU+us9uXzvzUcOY9RkegS21RUgoRvtQIm42qJosS3jJrFqJ5ZHyi0Dw/frpDmgw=="
},
+ "node_modules/file-selector": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/file-selector/-/file-selector-2.1.2.tgz",
+ "integrity": "sha512-QgXo+mXTe8ljeqUFaX3QVHc5osSItJ/Km+xpocx0aSqWGMSCf6qYs/VnzZgS864Pjn5iceMRFigeAV7AfTlaig==",
+ "license": "MIT",
+ "dependencies": {
+ "tslib": "^2.7.0"
+ },
+ "engines": {
+ "node": ">= 12"
+ }
+ },
"node_modules/filelist": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz",
@@ -18616,6 +18638,23 @@
"react": "^18.3.1"
}
},
+ "node_modules/react-dropzone": {
+ "version": "14.3.5",
+ "resolved": "https://registry.npmjs.org/react-dropzone/-/react-dropzone-14.3.5.tgz",
+ "integrity": "sha512-9nDUaEEpqZLOz5v5SUcFA0CjM4vq8YbqO0WRls+EYT7+DvxUdzDPKNCPLqGfj3YL9MsniCLCD4RFA6M95V6KMQ==",
+ "license": "MIT",
+ "dependencies": {
+ "attr-accept": "^2.2.4",
+ "file-selector": "^2.1.0",
+ "prop-types": "^15.8.1"
+ },
+ "engines": {
+ "node": ">= 10.13"
+ },
+ "peerDependencies": {
+ "react": ">= 16.8 || 18.0.0"
+ }
+ },
"node_modules/react-i18next": {
"version": "15.1.3",
"resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-15.1.3.tgz",
diff --git a/package.json b/package.json
index 2f412f41c3..1986528f96 100644
--- a/package.json
+++ b/package.json
@@ -55,6 +55,7 @@
"qrcode": "^1.5.4",
"react": "^18.3.0",
"react-dom": "^18.3.1",
+ "react-dropzone": "^14.3.5",
"react-i18next": "^15.1.3",
"react-lottie-player": "^2.1.0",
"react-pdf-html": "^2.1.2",
diff --git a/src/components/icons/IconBackupOrganized.tsx b/src/components/icons/IconBackupOrganized.tsx
new file mode 100644
index 0000000000..30f22d117f
--- /dev/null
+++ b/src/components/icons/IconBackupOrganized.tsx
@@ -0,0 +1,58 @@
+import { SvgIcon, SxProps, Theme } from '@mui/material';
+
+type IconProps = {
+ color?: string;
+ width?: number;
+ height?: number;
+ sx?: SxProps;
+ className?: string;
+};
+
+const IconBackupOrganized = ({
+ color,
+ width = 24,
+ height = 24,
+ sx = {},
+ className,
+}: IconProps) => {
+ return (
+
+
+
+ );
+};
+
+export default IconBackupOrganized;
diff --git a/src/components/icons/IconImportExport.tsx b/src/components/icons/IconImportExport.tsx
new file mode 100644
index 0000000000..e01c1e72ac
--- /dev/null
+++ b/src/components/icons/IconImportExport.tsx
@@ -0,0 +1,52 @@
+import { SvgIcon, SxProps, Theme } from '@mui/material';
+
+type IconProps = {
+ color?: string;
+ width?: number;
+ height?: number;
+ sx?: SxProps;
+ className?: string;
+};
+
+const IconImportExport = ({
+ color = '#222222',
+ width = 24,
+ height = 24,
+ sx = {},
+ className,
+}: IconProps) => {
+ return (
+
+
+
+ );
+};
+
+export default IconImportExport;
diff --git a/src/components/icons/IconImportJson.tsx b/src/components/icons/IconImportJson.tsx
new file mode 100644
index 0000000000..381f1abda2
--- /dev/null
+++ b/src/components/icons/IconImportJson.tsx
@@ -0,0 +1,52 @@
+import { SvgIcon, SxProps, Theme } from '@mui/material';
+
+type IconProps = {
+ color?: string;
+ width?: number;
+ height?: number;
+ sx?: SxProps;
+ className?: string;
+};
+
+const IconImportJson = ({
+ color,
+ width = 24,
+ height = 24,
+ sx = {},
+ className,
+}: IconProps) => {
+ return (
+
+
+
+ );
+};
+
+export default IconImportJson;
diff --git a/src/components/icons/index.ts b/src/components/icons/index.ts
index e9f4ffbd62..9c21497824 100644
--- a/src/components/icons/index.ts
+++ b/src/components/icons/index.ts
@@ -21,6 +21,7 @@ export { default as IconAttractions } from './IconAttractions';
export { default as IconAudioMixer } from './IconAudioMixer';
export { default as IconAuxiliaryPioneer } from './IconAuxiliaryPioneer';
export { default as IconBack } from './IconBack';
+export { default as IconBackupOrganized } from './IconBackupOrganized';
export { default as IconBrother } from './IconBrother';
export { default as IconCalendarMonth } from './IconCalendarMonth';
export { default as IconCalendarWeek } from './IconCalendarWeek';
@@ -120,7 +121,9 @@ export { default as IconImage } from './IconImage';
export { default as IconImgAdd } from './IconImgAdd';
export { default as IconImgDelete } from './IconImgDelete';
export { default as IconImgRotate } from './IconImgRotate';
+export { default as IconImportExport } from './IconImportExport';
export { default as IconImportFile } from './IconImportFile';
+export { default as IconImportJson } from './IconImportJson';
export { default as IconInTerritory } from './IconInTerritory';
export { default as IconInfo } from './IconInfo';
export { default as IconInformationBoard } from './IconInformationBoard';
@@ -187,8 +190,8 @@ export { default as IconPause } from './IconPause';
export { default as IconPermissionsPending } from './IconPermissionsPending';
export { default as IconPersonSearch } from './IconPersonSearch';
export { default as IconPerson } from './IconPerson';
-export { default as IconPersonPlaceholder } from './IconPersonPlaceholder';
export { default as IconPersonalDay } from './IconPersonalDay';
+export { default as IconPersonPlaceholder } from './IconPersonPlaceholder';
export { default as IconPhone } from './IconPhone';
export { default as IconPinCode } from './IconPinCode';
export { default as IconPin } from './IconPin';
diff --git a/src/features/congregation/settings/import_export/export/index.tsx b/src/features/congregation/settings/import_export/export/index.tsx
new file mode 100644
index 0000000000..54d4434b3a
--- /dev/null
+++ b/src/features/congregation/settings/import_export/export/index.tsx
@@ -0,0 +1,50 @@
+import { Box, Stack } from '@mui/material';
+import { IconBackupOrganized, IconLoading } from '@components/icons';
+import { useAppTranslation } from '@hooks/index';
+import { ExportType } from './index.types';
+import useExport from './useExport';
+import Button from '@components/button';
+import Typography from '@components/typography';
+
+const Export = (props: ExportType) => {
+ const { t } = useAppTranslation();
+
+ const { filename, isProcessing, handleDownload } = useExport();
+
+ return (
+
+
+
+
+
+ {filename}
+
+
+
+
+
+ }
+ >
+ {t('tr_download')}
+
+
+
+
+ );
+};
+
+export default Export;
diff --git a/src/features/congregation/settings/import_export/export/index.types.ts b/src/features/congregation/settings/import_export/export/index.types.ts
new file mode 100644
index 0000000000..8a10b979a4
--- /dev/null
+++ b/src/features/congregation/settings/import_export/export/index.types.ts
@@ -0,0 +1,3 @@
+export type ExportType = {
+ onClose: VoidFunction;
+};
diff --git a/src/features/congregation/settings/import_export/export/useExport.tsx b/src/features/congregation/settings/import_export/export/useExport.tsx
new file mode 100644
index 0000000000..1c9f264edf
--- /dev/null
+++ b/src/features/congregation/settings/import_export/export/useExport.tsx
@@ -0,0 +1,99 @@
+import { useMemo, useState } from 'react';
+import { useRecoilValue } from 'recoil';
+import { saveAs } from 'file-saver';
+import { formatDate } from '@services/dateformat';
+import { displaySnackNotification } from '@services/recoil/app';
+import { getMessageByCode } from '@services/i18n/translation';
+import { personsState } from '@states/persons';
+import { settingsState } from '@states/settings';
+import { branchCongAnalysisState } from '@states/branch_cong_analysis';
+import { branchFieldReportsState } from '@states/branch_field_service_reports';
+import { congFieldServiceReportsState } from '@states/field_service_reports';
+import { fieldGroupsState } from '@states/field_service_groups';
+import { meetingAttendanceState } from '@states/meeting_attendance';
+import { schedulesState } from '@states/schedules';
+import { sourcesState } from '@states/sources';
+import { speakersCongregationsActiveState } from '@states/speakers_congregations';
+import { visitingSpeakersActiveState } from '@states/visiting_speakers';
+
+const useExport = () => {
+ const persons = useRecoilValue(personsState);
+ const settings = useRecoilValue(settingsState);
+ const branchCongAnalysis = useRecoilValue(branchCongAnalysisState);
+ const branchFieldReports = useRecoilValue(branchFieldReportsState);
+ const congFieldReports = useRecoilValue(congFieldServiceReportsState);
+ const fieldServiceGroups = useRecoilValue(fieldGroupsState);
+ const meetingAttendance = useRecoilValue(meetingAttendanceState);
+ const schedules = useRecoilValue(schedulesState);
+ const sources = useRecoilValue(sourcesState);
+ const visitingSpeakers = useRecoilValue(visitingSpeakersActiveState);
+ const speakersCongregations = useRecoilValue(
+ speakersCongregationsActiveState
+ );
+
+ const [isProcessing, setIsProcessing] = useState(false);
+
+ const filename = useMemo(() => {
+ const now = formatDate(new Date(), 'yyyy-MM-dd_HH:mm:ss').replace('_', 'T');
+
+ return `Organized-backup-${now}.json`;
+ }, []);
+
+ const handleGetSettings = () => {
+ const app_settings = structuredClone(settings);
+
+ app_settings.cong_settings.cong_master_key = undefined;
+ app_settings.cong_settings.cong_access_code = undefined;
+
+ return app_settings;
+ };
+
+ const handleDownload = async () => {
+ if (isProcessing) return;
+
+ try {
+ setIsProcessing(true);
+
+ const backupData = {
+ name: 'Organized',
+ exported: new Date().toISOString(),
+ version: import.meta.env.PACKAGE_VERSION,
+ data: {
+ app_settings: handleGetSettings(),
+ branch_cong_analysis: branchCongAnalysis,
+ branch_field_service_reports: branchFieldReports,
+ cong_field_service_reports: congFieldReports,
+ field_service_groups: fieldServiceGroups,
+ meeting_attendance: meetingAttendance,
+ persons: persons.filter((record) => !record._deleted.value),
+ sched: schedules,
+ sources,
+ speakers_congregations: speakersCongregations,
+ visiting_speakers: visitingSpeakers,
+ },
+ };
+
+ const prettyJsonData = JSON.stringify(backupData, null, 2);
+
+ const blob = new Blob([prettyJsonData], { type: 'application/json' });
+
+ saveAs(blob, filename);
+
+ setIsProcessing(false);
+ } catch (error) {
+ setIsProcessing(false);
+
+ console.error(error);
+
+ displaySnackNotification({
+ severity: 'error',
+ header: getMessageByCode('error_app_generic-title'),
+ message: getMessageByCode(error.message),
+ });
+ }
+ };
+
+ return { filename, isProcessing, handleDownload };
+};
+
+export default useExport;
diff --git a/src/features/congregation/settings/import_export/import/index.tsx b/src/features/congregation/settings/import_export/import/index.tsx
new file mode 100644
index 0000000000..fc09735ff5
--- /dev/null
+++ b/src/features/congregation/settings/import_export/import/index.tsx
@@ -0,0 +1,64 @@
+import { Box, Stack } from '@mui/material';
+import { IconImportJson } from '@components/icons';
+import { useAppTranslation } from '@hooks/index';
+import { ImportType } from './index.types';
+import useImport from './useImport';
+import Button from '@components/button';
+import Typography from '@components/typography';
+
+const Import = (props: ImportType) => {
+ const { t } = useAppTranslation();
+
+ const { getInputProps, getRootProps } = useImport();
+
+ return (
+
+
+
+
+
+
+
+
+ {t('tr_dragOrClick')}
+
+
+
+ {t('tr_uploadJsonFile')}
+
+
+
+
+
+
+
+
+
+ );
+};
+
+export default Import;
diff --git a/src/features/congregation/settings/import_export/import/index.types.ts b/src/features/congregation/settings/import_export/import/index.types.ts
new file mode 100644
index 0000000000..68e7043985
--- /dev/null
+++ b/src/features/congregation/settings/import_export/import/index.types.ts
@@ -0,0 +1,3 @@
+export type ImportType = {
+ onClose: VoidFunction;
+};
diff --git a/src/features/congregation/settings/import_export/import/useImport.tsx b/src/features/congregation/settings/import_export/import/useImport.tsx
new file mode 100644
index 0000000000..b14dba3b7f
--- /dev/null
+++ b/src/features/congregation/settings/import_export/import/useImport.tsx
@@ -0,0 +1,47 @@
+import { useCallback } from 'react';
+import { FileWithPath, useDropzone } from 'react-dropzone';
+import { displaySnackNotification } from '@services/recoil/app';
+import { getMessageByCode } from '@services/i18n/translation';
+
+const useImport = () => {
+ const onDrop = useCallback(async (acceptedFiles: FileWithPath[]) => {
+ try {
+ if (acceptedFiles.length !== 1) {
+ displaySnackNotification({
+ severity: 'error',
+ header: getMessageByCode('error_app_generic-title'),
+ message: getMessageByCode('error_app_data_invalid-file'),
+ });
+
+ return;
+ }
+
+ const file = acceptedFiles.at(0);
+
+ const rawData = await file.text();
+ const data = JSON.parse(rawData);
+
+ console.log(data);
+ } catch (error) {
+ console.error(error);
+
+ displaySnackNotification({
+ severity: 'error',
+ header: getMessageByCode('error_app_generic-title'),
+ message: getMessageByCode(error.message),
+ });
+ }
+ }, []);
+
+ const { getRootProps, getInputProps } = useDropzone({
+ onDrop,
+ accept: { 'text/json': ['.json'] },
+ maxFiles: 1,
+ maxSize: 20971520,
+ multiple: false,
+ });
+
+ return { getRootProps, getInputProps };
+};
+
+export default useImport;
diff --git a/src/features/congregation/settings/import_export/index.tsx b/src/features/congregation/settings/import_export/index.tsx
new file mode 100644
index 0000000000..ab5aa67253
--- /dev/null
+++ b/src/features/congregation/settings/import_export/index.tsx
@@ -0,0 +1,31 @@
+import { Box, Stack } from '@mui/material';
+import { useAppTranslation } from '@hooks/index';
+import { ImportExportType } from './index.types';
+import useImportExport from './useImportExport';
+import Dialog from '@components/dialog';
+import Typography from '@components/typography';
+import Tabs from '@components/tabs';
+
+const ImportExport = (props: ImportExportType) => {
+ const { t } = useAppTranslation();
+
+ const { tabs, handleTabChange, value } = useImportExport(props);
+
+ return (
+
+ );
+};
+
+export default ImportExport;
diff --git a/src/features/congregation/settings/import_export/index.types.ts b/src/features/congregation/settings/import_export/index.types.ts
new file mode 100644
index 0000000000..62fbcd40da
--- /dev/null
+++ b/src/features/congregation/settings/import_export/index.types.ts
@@ -0,0 +1,4 @@
+export type ImportExportType = {
+ open: boolean;
+ onClose: VoidFunction;
+};
diff --git a/src/features/congregation/settings/import_export/useImportExport.tsx b/src/features/congregation/settings/import_export/useImportExport.tsx
new file mode 100644
index 0000000000..522014e4a1
--- /dev/null
+++ b/src/features/congregation/settings/import_export/useImportExport.tsx
@@ -0,0 +1,30 @@
+import { useMemo, useState } from 'react';
+import { useAppTranslation } from '@hooks/index';
+import { ImportExportType } from './index.types';
+import Import from './import';
+import Export from './export';
+
+const useImportExport = ({ onClose }: ImportExportType) => {
+ const { t } = useAppTranslation();
+
+ const [value, setValue] = useState(0);
+
+ const tabs = useMemo(() => {
+ return [
+ {
+ label: t('tr_export'),
+ Component: ,
+ },
+ {
+ label: t('tr_import'),
+ Component: ,
+ },
+ ];
+ }, [t, onClose]);
+
+ const handleTabChange = (tab: number) => setValue(tab);
+
+ return { tabs, value, handleTabChange };
+};
+
+export default useImportExport;
diff --git a/src/locales/en/congregation.json b/src/locales/en/congregation.json
index 9fda38d2d6..bd70a16421 100644
--- a/src/locales/en/congregation.json
+++ b/src/locales/en/congregation.json
@@ -439,5 +439,14 @@
"tr_addUserSyncNeededDesc": "To add more users to your congregation, enable the congregation sync feature. This allows you to add more users and devices for better collaboration. You can turn this feature on or off anytime in the congregation settings.",
"tr_deleteCongregationDesc": "Are you sure to delete your congregation from Organized? This will completely remove all your congregation data and there is no way to recover them anymore. All user accounts linked to your congregation will also be deleted. Enter below the congregation master key to confirm the deletion.",
"tr_deleteCongregationMasterKeyRequired": "Enter the master key",
- "tr_entranceAttendant": "Entrance attendant"
+ "tr_entranceAttendant": "Entrance attendant",
+ "tr_importExportTitle": "Import or export congregation data",
+ "tr_exportDesc": "Export your congregation data to create a local backup or transfer it to another app.",
+ "tr_importDesc": "Upload a file to import. Consider exporting your current data first to keep a backup for potential restoration later.",
+ "tr_ministryReports": "Ministry reports",
+ "tr_midweekMeetingHistory": "Midweek meeting history",
+ "tr_weekendMeetingHistory": "Weekend meeting history",
+ "tr_visitingSpeakers": "Visiting speakers",
+ "tr_dragOrClick": "Drag or click to upload",
+ "tr_uploadJsonFile": "Upload a file in JSON format"
}
diff --git a/src/locales/en/errors.json b/src/locales/en/errors.json
index 8ef44a85da..3125b4e2c7 100644
--- a/src/locales/en/errors.json
+++ b/src/locales/en/errors.json
@@ -15,5 +15,6 @@
"error_app_persons_spiritual-status-change": "Cannot change spiritual status",
"error_app_persons_spiritual-status-baptized-unbaptized": "A baptized publisher cannot be changed to unbaptized.",
"error_app_persons_spiritual-status-baptized-midweek": "A baptized publisher cannot be changed to midweek student.",
- "error_app_persons_spiritual-status-unbaptized-midweek": "An unbaptized publisher cannot be changed to midweek student."
+ "error_app_persons_spiritual-status-unbaptized-midweek": "An unbaptized publisher cannot be changed to midweek student.",
+ "error_app_data_invalid-file": "Unable to recognize the file you are trying to import."
}
diff --git a/src/locales/en/general.json b/src/locales/en/general.json
index 8004a4494e..1c9b62e54e 100644
--- a/src/locales/en/general.json
+++ b/src/locales/en/general.json
@@ -129,5 +129,7 @@
"tr_appliesOnlyToBrothers": "Applies only to brothers",
"tr_circuit": "Circuit: {{ circuitNumber }}",
"tr_ageInYearsAndMonths": "{{ years }} years, {{months}} months",
- "tr_personHasNoAssignmentHistory": "This person has no assignment history yet"
+ "tr_personHasNoAssignmentHistory": "This person has no assignment history yet",
+ "tr_download": "Download",
+ "tr_import": "Import"
}
diff --git a/src/pages/congregation/settings/index.tsx b/src/pages/congregation/settings/index.tsx
index 8c701b3519..d47d38f74e 100644
--- a/src/pages/congregation/settings/index.tsx
+++ b/src/pages/congregation/settings/index.tsx
@@ -1,21 +1,29 @@
import { Box } from '@mui/material';
import { useAppTranslation, useBreakpoints } from '@hooks/index';
+import useCongregationSettings from './useCongregationSettings';
import CircuitOverseer from '@features/congregation/settings/circuit_overseer';
import CongregationBasic from '@features/congregation/settings/congregation_basic';
import CongregationPrivacy from '@features/congregation/settings/congregation_privacy';
import MeetingForms from '@features/congregation/settings/meeting_forms';
import MinistrySettings from '@features/congregation/settings/ministry_settings';
import PageTitle from '@components/page_title';
+import ImportExport from '@features/congregation/settings/import_export';
const CongregationSettings = () => {
const { t } = useAppTranslation();
const { desktopUp } = useBreakpoints();
+ const { handleCloseExchange, isDataExchangeOpen } = useCongregationSettings();
+
return (
+ {isDataExchangeOpen && (
+
+ )}
+
{
+ const [isDataExchangeOpen, setIsDataExchangeOpen] = useState(false);
+
+ const handleOpenExchange = () => setIsDataExchangeOpen(true);
+
+ const handleCloseExchange = () => setIsDataExchangeOpen(false);
+
+ return { isDataExchangeOpen, handleOpenExchange, handleCloseExchange };
+};
+
+export default useCongregationSettings;
diff --git a/src/pages/meetings/schedules/index.tsx b/src/pages/meetings/schedules/index.tsx
index 65893e17c0..66780215f3 100644
--- a/src/pages/meetings/schedules/index.tsx
+++ b/src/pages/meetings/schedules/index.tsx
@@ -1,56 +1,13 @@
-import { useMemo } from 'react';
-import { useRecoilValue } from 'recoil';
import { Box } from '@mui/material';
-import { useAppTranslation, useCurrentUser } from '@hooks/index';
-import { settingsState, userDataViewState } from '@states/settings';
+import { useAppTranslation } from '@hooks/index';
import useWeeklySchedules from './useWeeklySchedules';
-import MidweekMeeting from '@features/meetings/weekly_schedules/midweek_meeting';
-import OutgoingTalks from '@features/meetings/weekly_schedules/outgoing_talks';
import PageTitle from '@components/page_title';
import ScrollableTabs from '@components/scrollable_tabs';
-import WeekendMeeting from '@features/meetings/weekly_schedules/weekend_meeting';
const WeeklySchedules = () => {
const { t } = useAppTranslation();
- const { value, handleScheduleChange } = useWeeklySchedules();
-
- const { isAppointed } = useCurrentUser();
-
- const settings = useRecoilValue(settingsState);
- const dataView = useRecoilValue(userDataViewState);
-
- const outgoingVisible = useMemo(() => {
- if (isAppointed) return true;
-
- const weekend = settings.cong_settings.weekend_meeting.find(
- (record) => record.type === dataView
- );
-
- return weekend.outgoing_talks_schedule_public.value;
- }, [isAppointed, settings, dataView]);
-
- const tabs = useMemo(() => {
- const result = [
- {
- label: t('tr_midweekMeeting'),
- Component: ,
- },
- {
- label: t('tr_weekendMeeting'),
- Component: ,
- },
- ];
-
- if (outgoingVisible) {
- result.push({
- label: t('tr_outgoingTalks'),
- Component: ,
- });
- }
-
- return result;
- }, [outgoingVisible, t]);
+ const { value, handleScheduleChange, tabs } = useWeeklySchedules();
return (
diff --git a/src/pages/meetings/schedules/useWeeklySchedules.tsx b/src/pages/meetings/schedules/useWeeklySchedules.tsx
index 49c5acaff5..262761728e 100644
--- a/src/pages/meetings/schedules/useWeeklySchedules.tsx
+++ b/src/pages/meetings/schedules/useWeeklySchedules.tsx
@@ -1,13 +1,21 @@
import { useMemo } from 'react';
-import { WeeklySchedulesType } from './index.types';
+import { useRecoilValue } from 'recoil';
+import { useAppTranslation, useCurrentUser } from '@hooks/index';
import { localStorageGetItem } from '@utils/common';
+import { WeeklySchedulesType } from './index.types';
+import { settingsState, userDataViewState } from '@states/settings';
+import MidweekMeeting from '@features/meetings/weekly_schedules/midweek_meeting';
+import WeekendMeeting from '@features/meetings/weekly_schedules/weekend_meeting';
+import OutgoingTalks from '@features/meetings/weekly_schedules/outgoing_talks';
const LOCALSTORAGE_KEY = 'organized_weekly_schedules';
+const scheduleType = localStorageGetItem(
+ LOCALSTORAGE_KEY
+) as WeeklySchedulesType;
+
const useWeeklySchedules = () => {
- const scheduleType = localStorageGetItem(
- LOCALSTORAGE_KEY
- ) as WeeklySchedulesType;
+ const { t } = useAppTranslation();
const value = useMemo(() => {
if (!scheduleType) return 0;
@@ -15,7 +23,44 @@ const useWeeklySchedules = () => {
if (scheduleType === 'midweek') return 0;
if (scheduleType === 'weekend') return 1;
if (scheduleType === 'outgoing') return 2;
- }, [scheduleType]);
+ }, []);
+
+ const { isAppointed } = useCurrentUser();
+
+ const settings = useRecoilValue(settingsState);
+ const dataView = useRecoilValue(userDataViewState);
+
+ const outgoingVisible = useMemo(() => {
+ if (isAppointed) return true;
+
+ const weekend = settings.cong_settings.weekend_meeting.find(
+ (record) => record.type === dataView
+ );
+
+ return weekend.outgoing_talks_schedule_public.value;
+ }, [isAppointed, settings, dataView]);
+
+ const tabs = useMemo(() => {
+ const result = [
+ {
+ label: t('tr_midweekMeeting'),
+ Component: ,
+ },
+ {
+ label: t('tr_weekendMeeting'),
+ Component: ,
+ },
+ ];
+
+ if (outgoingVisible) {
+ result.push({
+ label: t('tr_outgoingTalks'),
+ Component: ,
+ });
+ }
+
+ return result;
+ }, [outgoingVisible, t]);
const handleScheduleChange = (value: number) => {
let type: WeeklySchedulesType;
@@ -27,7 +72,7 @@ const useWeeklySchedules = () => {
localStorage.setItem(LOCALSTORAGE_KEY, type!);
};
- return { value, handleScheduleChange };
+ return { value, handleScheduleChange, tabs };
};
export default useWeeklySchedules;
diff --git a/src/services/app/sources.ts b/src/services/app/sources.ts
index 23c811a242..fe5670be6e 100644
--- a/src/services/app/sources.ts
+++ b/src/services/app/sources.ts
@@ -20,7 +20,8 @@ import {
sourcesJWAutoImportState,
} from '@states/settings';
import { SourceFrequency } from '@definition/settings';
-import { addWeeks } from '@utils/date';
+import { addWeeks, getWeekDate } from '@utils/date';
+import { formatDate } from '@services/dateformat';
export const sourcesImportEPUB = async (fileEPUB) => {
const data = await loadEPUB(fileEPUB);
@@ -60,161 +61,204 @@ const sourcesFormatAndSaveData = async (data: SourceWeekIncomingType[]) => {
obj.weekOf = src.mwb_week_date || src.w_study_date || src.week_date;
- if (isMWB) {
- let assType: number;
- const assTypeList: AssignmentAYFOnlyType[] = await promiseGetRecoil(
- assignmentTypeAYFOnlyState
- );
-
- obj.midweek_meeting = {} as SourceWeekType['midweek_meeting'];
-
- obj.midweek_meeting.week_date_locale = {
- [source_lang]: src.mwb_week_date_locale,
- };
- obj.midweek_meeting.weekly_bible_reading = {
- [source_lang]: src.mwb_weekly_bible_reading,
- };
- obj.midweek_meeting.song_first = {
- [source_lang]: src.mwb_song_first.toString(),
- };
- obj.midweek_meeting.tgw_talk = {
- src: { [source_lang]: src.mwb_tgw_talk_title },
- time: { default: 10, override: [] },
- };
- obj.midweek_meeting.tgw_gems = {
- title: { [source_lang]: src.mwb_tgw_gems_title },
- time: { default: 10, override: [] },
- };
- obj.midweek_meeting.tgw_bible_reading = {
- src: { [source_lang]: src.mwb_tgw_bread },
- title: { [source_lang]: src.mwb_tgw_bread_title },
- };
-
- const cnAYF = src.mwb_ayf_count;
- obj.midweek_meeting.ayf_count = { [source_lang]: src.mwb_ayf_count };
-
- assType =
- assTypeList.find((type) => type.label === src.mwb_ayf_part1_type)
- ?.value || 127;
- obj.midweek_meeting.ayf_part1 = {
- src: { [source_lang]: src.mwb_ayf_part1 },
- time: { [source_lang]: src.mwb_ayf_part1_time },
- title: { [source_lang]: src.mwb_ayf_part1_title },
- type: { [source_lang]: assType },
- };
-
- if (cnAYF > 1) {
- assType =
- assTypeList.find((type) => type.label === src.mwb_ayf_part2_type)
- ?.value || 127;
- obj.midweek_meeting.ayf_part2 = {
- src: { [source_lang]: src.mwb_ayf_part2 },
- time: { [source_lang]: src.mwb_ayf_part2_time },
- title: { [source_lang]: src.mwb_ayf_part2_title },
- type: { [source_lang]: assType },
- };
- }
+ const mondayDate = formatDate(
+ getWeekDate(new Date(obj.weekOf)),
+ 'yyyy/MM/dd'
+ );
- if (cnAYF > 2) {
- assType =
- assTypeList.find((type) => type.label === src.mwb_ayf_part3_type)
- ?.value || 127;
- obj.midweek_meeting.ayf_part3 = {
- src: { [source_lang]: src.mwb_ayf_part3 },
- time: { [source_lang]: src.mwb_ayf_part3_time },
- title: { [source_lang]: src.mwb_ayf_part3_title },
- type: { [source_lang]: assType },
+ if (mondayDate === obj.weekOf) {
+ if (isMWB) {
+ let assType: number;
+ const assTypeList: AssignmentAYFOnlyType[] = await promiseGetRecoil(
+ assignmentTypeAYFOnlyState
+ );
+
+ obj.midweek_meeting = {} as SourceWeekType['midweek_meeting'];
+
+ obj.midweek_meeting.week_date_locale = {
+ [source_lang]: src.mwb_week_date_locale,
};
- }
+ obj.midweek_meeting.weekly_bible_reading = {
+ [source_lang]: src.mwb_weekly_bible_reading,
+ };
+ obj.midweek_meeting.song_first = {
+ [source_lang]: src.mwb_song_first.toString(),
+ };
+ obj.midweek_meeting.tgw_talk = {
+ src: { [source_lang]: src.mwb_tgw_talk_title },
+ time: { default: 10, override: [] },
+ };
+ obj.midweek_meeting.tgw_gems = {
+ title: { [source_lang]: src.mwb_tgw_gems_title },
+ time: { default: 10, override: [] },
+ };
+ obj.midweek_meeting.tgw_bible_reading = {
+ src: { [source_lang]: src.mwb_tgw_bread },
+ title: { [source_lang]: src.mwb_tgw_bread_title },
+ };
+
+ const cnAYF = src.mwb_ayf_count;
+ obj.midweek_meeting.ayf_count = { [source_lang]: src.mwb_ayf_count };
- if (cnAYF > 3) {
assType =
- assTypeList.find((type) => type.label === src.mwb_ayf_part4_type)
+ assTypeList.find((type) => type.label === src.mwb_ayf_part1_type)
?.value || 127;
- obj.midweek_meeting.ayf_part4 = {
- src: { [source_lang]: src.mwb_ayf_part4 },
- time: { [source_lang]: src.mwb_ayf_part4_time },
- title: { [source_lang]: src.mwb_ayf_part4_title },
+
+ if (
+ source_lang === 'TG' &&
+ obj.weekOf >= '2024/01/01' &&
+ assType === 102
+ ) {
+ assType = 124;
+ }
+
+ obj.midweek_meeting.ayf_part1 = {
+ src: { [source_lang]: src.mwb_ayf_part1 },
+ time: { [source_lang]: src.mwb_ayf_part1_time },
+ title: { [source_lang]: src.mwb_ayf_part1_title },
type: { [source_lang]: assType },
};
- }
- obj.midweek_meeting.song_middle = {
- [source_lang]: src.mwb_song_middle.toString(),
- };
- obj.midweek_meeting.lc_count = {
- default: { [source_lang]: src.mwb_lc_count },
- override: [],
- };
- obj.midweek_meeting.lc_part1 = {
- title: {
- default: { [source_lang]: src.mwb_lc_part1_title },
- override: [],
- },
- time: {
- default: { [source_lang]: src.mwb_lc_part1_time },
- override: [],
- },
- desc: {
- default: { [source_lang]: src.mwb_lc_part1_content },
+ if (cnAYF > 1) {
+ assType =
+ assTypeList.find((type) => type.label === src.mwb_ayf_part2_type)
+ ?.value || 127;
+
+ if (
+ source_lang === 'TG' &&
+ obj.weekOf >= '2024/01/01' &&
+ assType === 102
+ ) {
+ assType = 124;
+ }
+
+ obj.midweek_meeting.ayf_part2 = {
+ src: { [source_lang]: src.mwb_ayf_part2 },
+ time: { [source_lang]: src.mwb_ayf_part2_time },
+ title: { [source_lang]: src.mwb_ayf_part2_title },
+ type: { [source_lang]: assType },
+ };
+ }
+
+ if (cnAYF > 2) {
+ assType =
+ assTypeList.find((type) => type.label === src.mwb_ayf_part3_type)
+ ?.value || 127;
+
+ if (
+ source_lang === 'TG' &&
+ obj.weekOf >= '2024/01/01' &&
+ assType === 102
+ ) {
+ assType = 124;
+ }
+
+ obj.midweek_meeting.ayf_part3 = {
+ src: { [source_lang]: src.mwb_ayf_part3 },
+ time: { [source_lang]: src.mwb_ayf_part3_time },
+ title: { [source_lang]: src.mwb_ayf_part3_title },
+ type: { [source_lang]: assType },
+ };
+ }
+
+ if (cnAYF > 3) {
+ assType =
+ assTypeList.find((type) => type.label === src.mwb_ayf_part4_type)
+ ?.value || 127;
+
+ if (
+ source_lang === 'TG' &&
+ obj.weekOf >= '2024/01/01' &&
+ assType === 102
+ ) {
+ assType = 124;
+ }
+
+ obj.midweek_meeting.ayf_part4 = {
+ src: { [source_lang]: src.mwb_ayf_part4 },
+ time: { [source_lang]: src.mwb_ayf_part4_time },
+ title: { [source_lang]: src.mwb_ayf_part4_title },
+ type: { [source_lang]: assType },
+ };
+ }
+
+ obj.midweek_meeting.song_middle = {
+ [source_lang]: src.mwb_song_middle.toString(),
+ };
+ obj.midweek_meeting.lc_count = {
+ default: { [source_lang]: src.mwb_lc_count },
override: [],
- },
- };
-
- if (src.mwb_lc_count > 1) {
- obj.midweek_meeting.lc_part2 = {
+ };
+ obj.midweek_meeting.lc_part1 = {
title: {
- default: { [source_lang]: src.mwb_lc_part2_title },
+ default: { [source_lang]: src.mwb_lc_part1_title },
override: [],
},
time: {
- default: { [source_lang]: src.mwb_lc_part2_time },
+ default: { [source_lang]: src.mwb_lc_part1_time },
override: [],
},
desc: {
- default: { [source_lang]: src.mwb_lc_part2_content },
+ default: { [source_lang]: src.mwb_lc_part1_content },
override: [],
},
};
- }
- obj.midweek_meeting.lc_cbs = {
- src: { [source_lang]: src.mwb_lc_cbs },
- time: { default: 30, override: [] },
- title: {
- default: { [source_lang]: src.mwb_lc_cbs_title },
+ if (src.mwb_lc_count > 1) {
+ obj.midweek_meeting.lc_part2 = {
+ title: {
+ default: { [source_lang]: src.mwb_lc_part2_title },
+ override: [],
+ },
+ time: {
+ default: { [source_lang]: src.mwb_lc_part2_time },
+ override: [],
+ },
+ desc: {
+ default: { [source_lang]: src.mwb_lc_part2_content },
+ override: [],
+ },
+ };
+ }
+
+ obj.midweek_meeting.lc_cbs = {
+ src: { [source_lang]: src.mwb_lc_cbs },
+ time: { default: 30, override: [] },
+ title: {
+ default: { [source_lang]: src.mwb_lc_cbs_title },
+ override: [],
+ },
+ };
+ obj.midweek_meeting.song_conclude = {
+ default: { [source_lang]: src.mwb_song_conclude.toString() },
override: [],
- },
- };
- obj.midweek_meeting.song_conclude = {
- default: { [source_lang]: src.mwb_song_conclude.toString() },
- override: [],
- };
- }
+ };
+ }
- if (isW) {
- obj.weekend_meeting = {} as SourceWeekType['weekend_meeting'];
-
- obj.weekend_meeting.song_first = [];
- obj.weekend_meeting.public_talk = [];
- obj.weekend_meeting.co_talk_title = {
- public: { src: '', updatedAt: '' },
- service: { src: '', updatedAt: '' },
- };
- obj.weekend_meeting.song_middle = {
- [source_lang]: src.w_study_opening_song.toString(),
- };
- obj.weekend_meeting.w_study = { [source_lang]: src.w_study_title };
- obj.weekend_meeting.song_conclude = {
- default: { [source_lang]: src.w_study_concluding_song.toString() },
- override: [],
- };
- }
+ if (isW) {
+ obj.weekend_meeting = {} as SourceWeekType['weekend_meeting'];
+
+ obj.weekend_meeting.song_first = [];
+ obj.weekend_meeting.public_talk = [];
+ obj.weekend_meeting.co_talk_title = {
+ public: { src: '', updatedAt: '' },
+ service: { src: '', updatedAt: '' },
+ };
+ obj.weekend_meeting.song_middle = {
+ [source_lang]: src.w_study_opening_song.toString(),
+ };
+ obj.weekend_meeting.w_study = { [source_lang]: src.w_study_title };
+ obj.weekend_meeting.song_conclude = {
+ default: { [source_lang]: src.w_study_concluding_song.toString() },
+ override: [],
+ };
+ }
- await dbSourcesSave(obj);
+ await dbSourcesSave(obj);
- // check if record exists in sched table
- await dbSchedCheck(obj.weekOf);
+ // check if record exists in sched table
+ await dbSchedCheck(obj.weekOf);
+ }
}
};
diff --git a/src/services/dexie/assignment.ts b/src/services/dexie/assignment.ts
index e0418c1830..8c1fcea96c 100644
--- a/src/services/dexie/assignment.ts
+++ b/src/services/dexie/assignment.ts
@@ -37,68 +37,144 @@ export const dbAssignmentUpdate = async () => {
const explainingBeliefsObj: { [language: string]: string } = {};
const dicussionObj: { [language: string]: string } = {};
- LANGUAGE_LIST.forEach((lang) => {
+ const appLang = localStorage.getItem('ui_lang') || 'en';
+ const langCode =
+ LANGUAGE_LIST.find((record) => record.locale === appLang)?.code || 'E';
+
+ const languages = [{ locale: appLang, code: langCode }];
+
+ if (!languages.some((r) => r.locale === 'en'))
+ languages.push({ locale: 'en', code: 'E' });
+
+ for (const lang of languages) {
const langCode = lang.code.toUpperCase();
- bReadObj[langCode] = getTranslation({ key: 'tr_bibleReading' });
- initCallObj[langCode] = getTranslation({ key: 'tr_initialCall' });
- rvObj[langCode] = getTranslation({ key: 'tr_returnVisit' });
- bsObj[langCode] = getTranslation({ key: 'tr_bibleStudy' });
- talkObj[langCode] = getTranslation({ key: 'tr_talk' });
- otherObj[langCode] = getTranslation({ key: 'tr_otherPart' });
- icVideoObj[langCode] = getTranslation({ key: 'tr_initialCallVideo' });
- rvVideoObj[langCode] = getTranslation({ key: 'tr_returnVisitVideo' });
- memorialObj[langCode] = getTranslation({ key: 'tr_memorialInvite' });
+ bReadObj[langCode] = getTranslation({
+ key: 'tr_bibleReading',
+ language: lang.locale,
+ });
+ initCallObj[langCode] = getTranslation({
+ key: 'tr_initialCall',
+ language: lang.locale,
+ });
+ rvObj[langCode] = getTranslation({
+ key: 'tr_returnVisit',
+ language: lang.locale,
+ });
+ bsObj[langCode] = getTranslation({
+ key: 'tr_bibleStudy',
+ language: lang.locale,
+ });
+ talkObj[langCode] = getTranslation({
+ key: 'tr_talk',
+ language: lang.locale,
+ });
+ otherObj[langCode] = getTranslation({
+ key: 'tr_otherPart',
+ language: lang.locale,
+ });
+ icVideoObj[langCode] = getTranslation({
+ key: 'tr_initialCallVideo',
+ language: lang.locale,
+ });
+ rvVideoObj[langCode] = getTranslation({
+ key: 'tr_returnVisitVideo',
+ language: lang.locale,
+ });
+ memorialObj[langCode] = getTranslation({
+ key: 'tr_memorialInvite',
+ language: lang.locale,
+ });
memorialVideoObj[langCode] = getTranslation({
key: 'tr_memorialInviteVideo',
- language: lang.code,
+ language: lang.locale,
});
chairmanMMObj[langCode] = getTranslation({
key: 'tr_chairmanMidweekMeeting',
- language: lang.code,
+ language: lang.locale,
+ });
+ prayerMMObj[langCode] = getTranslation({
+ key: 'tr_prayerMidweekMeeting',
+ language: lang.locale,
+ });
+ tgwTalkObj[langCode] = getTranslation({
+ key: 'tr_tgwTalk',
+ language: lang.locale,
+ });
+ tgwGemsObj[langCode] = getTranslation({
+ key: 'tr_tgwGems',
+ language: lang.locale,
+ });
+ lcPartObj[langCode] = getTranslation({
+ key: 'tr_lcPart',
+ language: lang.locale,
+ });
+ cbsConductorObj[langCode] = getTranslation({
+ key: 'tr_cbsConductor',
+ language: lang.locale,
+ });
+ cbsReaderObj[langCode] = getTranslation({
+ key: 'tr_cbsReader',
+ language: lang.locale,
});
- prayerMMObj[langCode] = getTranslation({ key: 'tr_prayerMidweekMeeting' });
- tgwTalkObj[langCode] = getTranslation({ key: 'tr_tgwTalk' });
- tgwGemsObj[langCode] = getTranslation({ key: 'tr_tgwGems' });
- lcPartObj[langCode] = getTranslation({ key: 'tr_lcPart' });
- cbsConductorObj[langCode] = getTranslation({ key: 'tr_cbsConductor' });
- cbsReaderObj[langCode] = getTranslation({ key: 'tr_cbsReader' });
initCallVariationsObj[langCode] = getTranslation({
key: 'tr_initialCallVariations',
+ language: lang.locale,
});
rvVariationsObj[langCode] = getTranslation({
key: 'tr_returnVisitVariations',
+ language: lang.locale,
});
chairmanWMObj[langCode] = getTranslation({
key: 'tr_chairmanWeekendMeeting',
+ language: lang.locale,
+ });
+ prayerWMObj[langCode] = getTranslation({
+ key: 'tr_prayerWeekendMeeting',
+ language: lang.locale,
+ });
+ speakerObj[langCode] = getTranslation({
+ key: 'tr_speaker',
+ language: lang.locale,
});
- prayerWMObj[langCode] = getTranslation({ key: 'tr_prayerWeekendMeeting' });
- speakerObj[langCode] = getTranslation({ key: 'tr_speaker' });
speakerSymposiumObj[langCode] = getTranslation({
key: 'tr_speakerSymposium',
+ language: lang.locale,
});
wtStudyReaderObj[langCode] = getTranslation({
key: 'tr_watchtowerStudyReader',
+ language: lang.locale,
});
wtStudyConductor[langCode] = getTranslation({
key: 'tr_watchtowerStudyConductor',
+ language: lang.locale,
});
auxClassroomMMObj[langCode] = getTranslation({
key: 'tr_auxClassCounselor',
+ language: lang.locale,
});
assistantOnlyMMObj[langCode] = getTranslation({ key: 'tr_assistantOnly' });
startingConversationObj[langCode] = getTranslation({
key: 'tr_startingConversation',
+ language: lang.locale,
+ });
+ followingUpObj[langCode] = getTranslation({
+ key: 'tr_followingUp',
+ language: lang.locale,
});
- followingUpObj[langCode] = getTranslation({ key: 'tr_followingUp' });
makingDisciplesObj[langCode] = getTranslation({
key: 'tr_makingDisciples',
+ language: lang.locale,
});
explainingBeliefsObj[langCode] = getTranslation({
key: 'tr_explainingBeliefs',
+ language: lang.locale,
});
- dicussionObj[langCode] = getTranslation({ key: 'tr_discussion' });
- });
+ dicussionObj[langCode] = getTranslation({
+ key: 'tr_discussion',
+ language: lang.locale,
+ });
+ }
await appDb.assignment.clear();
diff --git a/src/services/dexie/weekType.ts b/src/services/dexie/weekType.ts
index af3fa938fd..efc4af578b 100644
--- a/src/services/dexie/weekType.ts
+++ b/src/services/dexie/weekType.ts
@@ -1,4 +1,3 @@
-import { LANGUAGE_LIST } from '@constants/index';
import { getTranslation } from '@services/i18n/translation';
import appDb from '@db/appDb';
@@ -11,17 +10,44 @@ export const dbWeekTypeUpdate = async () => {
const specialTalkWeekObj = {};
const noMeetingWeekObj = {};
- LANGUAGE_LIST.forEach((lang) => {
- const locale = lang.locale.toUpperCase();
+ const language = localStorage.getItem('ui_lang') || 'en';
- normWeekObj[locale] = getTranslation({ key: 'tr_normalWeek' });
- tgWeekObj[locale] = getTranslation({ key: 'tr_circuitOverseerWeek' });
- caWeekObj[locale] = getTranslation({ key: 'tr_assemblyWeek' });
- coWeekObj[locale] = getTranslation({ key: 'tr_conventionWeek' });
- memorialWeekObj[locale] = getTranslation({ key: 'tr_memorialWeek' });
- specialTalkWeekObj[locale] = getTranslation({ key: 'tr_specialTalkWeek' });
- noMeetingWeekObj[locale] = getTranslation({ key: 'tr_noMeeting' });
- });
+ const languages = [language];
+
+ if (!languages.includes('en')) languages.push('en');
+
+ for (const lang of languages) {
+ const locale = lang.toUpperCase();
+
+ normWeekObj[locale] = getTranslation({
+ key: 'tr_normalWeek',
+ language: lang,
+ });
+ tgWeekObj[locale] = getTranslation({
+ key: 'tr_circuitOverseerWeek',
+ language: lang,
+ });
+ caWeekObj[locale] = getTranslation({
+ key: 'tr_assemblyWeek',
+ language: lang,
+ });
+ coWeekObj[locale] = getTranslation({
+ key: 'tr_conventionWeek',
+ language: lang,
+ });
+ memorialWeekObj[locale] = getTranslation({
+ key: 'tr_memorialWeek',
+ language: lang,
+ });
+ specialTalkWeekObj[locale] = getTranslation({
+ key: 'tr_specialTalkWeek',
+ language: lang,
+ });
+ noMeetingWeekObj[locale] = getTranslation({
+ key: 'tr_noMeeting',
+ language: lang,
+ });
+ }
await appDb.week_type.clear();
diff --git a/src/services/worker/backupUtils.ts b/src/services/worker/backupUtils.ts
index f6f6d00122..9a16227351 100644
--- a/src/services/worker/backupUtils.ts
+++ b/src/services/worker/backupUtils.ts
@@ -851,6 +851,16 @@ const dbRestoreSources = async (
const newItem = structuredClone(localItem);
syncFromRemote(newItem, remoteItem);
+ // give priority to local type
+ newItem.midweek_meeting.ayf_part1.type =
+ localItem.midweek_meeting.ayf_part1.type;
+ newItem.midweek_meeting.ayf_part2.type =
+ localItem.midweek_meeting.ayf_part2.type;
+ newItem.midweek_meeting.ayf_part3.type =
+ localItem.midweek_meeting.ayf_part3.type;
+ newItem.midweek_meeting.ayf_part4.type =
+ localItem.midweek_meeting.ayf_part4.type;
+
dataToUpdate.push(newItem);
}
}