diff --git a/src/features/schedules/AutofillSchedule.jsx b/src/features/schedules/AutofillSchedule.jsx index 6f21f639d1..bc3bf903fd 100644 --- a/src/features/schedules/AutofillSchedule.jsx +++ b/src/features/schedules/AutofillSchedule.jsx @@ -16,11 +16,12 @@ import { isAutoFillSchedState, reloadWeekSummaryState, } from '../../states/schedule'; -import { dbGetSourceMaterial } from '../../indexedDb/dbSourceMaterial'; +import { checkCBSReader, checkLCAssignments, dbGetSourceMaterial } from '../../indexedDb/dbSourceMaterial'; import { dbFetchScheduleInfo, dbGetScheduleData } from '../../indexedDb/dbSchedule'; import { dbSaveAss } from '../../indexedDb/dbAssignment'; import { dbGetAppSettings } from '../../indexedDb/dbAppSettings'; import { dbGetPersonsByAssType } from '../../indexedDb/dbPersons'; +import { openingPrayerAutoAssignState } from '../../states/congregation'; const AutofillSchedule = () => { const { t } = useTranslation('ui'); @@ -32,6 +33,7 @@ const AutofillSchedule = () => { const isAutofillSched = useRecoilValue(isAutoFillSchedState); const currentSchedule = useRecoilValue(currentScheduleState); const currentWeek = useRecoilValue(currentWeekSchedState); + const autoAssignOpeningPrayer = useRecoilValue(openingPrayerAutoAssignState); const [totalToAssign, setTotalToAssign] = useState(0); const [assigned, setAssigned] = useState(0); @@ -72,6 +74,13 @@ const AutofillSchedule = () => { setAssigned((prev) => { return prev + 1; }); + + if (autoAssignOpeningPrayer) { + await dbSaveAss(week, chairmanA, 'opening_prayer'); + setAssigned((prev) => { + return prev + 1; + }); + } } // Aux Class @@ -132,23 +141,28 @@ const AutofillSchedule = () => { }); } - // Assign LC Part 1 - students = await dbGetPersonsByAssType(114); - if (students.length > 0) { - const lcPart1 = students[0].person_uid; - await dbSaveAss(week, lcPart1, 'lc_part1'); - setAssigned((prev) => { - return prev + 1; - }); + const noAssignLC1 = await checkLCAssignments(sourceData.lcPart1_src); + if (!noAssignLC1) { + // Assign LC Part 1 + students = await dbGetPersonsByAssType(114); + if (students.length > 0) { + const lcPart1 = students[0].person_uid; + await dbSaveAss(week, lcPart1, 'lc_part1'); + setAssigned((prev) => { + return prev + 1; + }); + } } // Assign LC Part 2 let isAssignLC2 = false; if (sourceData.lcCount_override === undefined && sourceData.lcCount === 2) { - isAssignLC2 = true; + const noAssignLC2 = await checkLCAssignments(sourceData.lcPart2_src); + isAssignLC2 = !noAssignLC2; } if (sourceData.lcCount_override !== undefined && sourceData.lcCount_override === 2) { - isAssignLC2 = true; + const noAssignLC2 = await checkLCAssignments(sourceData.lcPart2_src_override); + isAssignLC2 = !noAssignLC2; } if (isAssignLC2) { @@ -164,26 +178,31 @@ const AutofillSchedule = () => { // Assign CBS Reader if (schedData.week_type === 1) { - students = await dbGetPersonsByAssType(116); + const noAssignCBSReader = await checkCBSReader(sourceData.cbs_src); + if (!noAssignCBSReader) { + students = await dbGetPersonsByAssType(116); + if (students.length > 0) { + const cbsReader = students[0].person_uid; + await dbSaveAss(week, cbsReader, 'cbs_reader'); + setAssigned((prev) => { + return prev + 1; + }); + } + } + } + + if (!autoAssignOpeningPrayer) { + // Assign Opening Prayer + students = await dbGetPersonsByAssType(111); if (students.length > 0) { - const cbsReader = students[0].person_uid; - await dbSaveAss(week, cbsReader, 'cbs_reader'); + const openingPrayer = students[0].person_uid; + await dbSaveAss(week, openingPrayer, 'opening_prayer'); setAssigned((prev) => { return prev + 1; }); } } - // Assign Opening Prayer - students = await dbGetPersonsByAssType(111); - if (students.length > 0) { - const openingPrayer = students[0].person_uid; - await dbSaveAss(week, openingPrayer, 'opening_prayer'); - setAssigned((prev) => { - return prev + 1; - }); - } - // Assign Closing Prayer students = await dbGetPersonsByAssType(111); if (students.length > 0) { diff --git a/src/features/schedules/ScheduleAssignment.jsx b/src/features/schedules/ScheduleAssignment.jsx index 0eaf517647..7c4e043d58 100644 --- a/src/features/schedules/ScheduleAssignment.jsx +++ b/src/features/schedules/ScheduleAssignment.jsx @@ -15,7 +15,7 @@ import ScheduleMeetingPart from './ScheduleMeetingPart'; import ScheduleRowAssignment from './ScheduleRowAssignment'; import SingleAssignment from './SingleAssignment'; import StudentSelector from './StudentSelector'; -import { classCountState } from '../../states/congregation'; +import { classCountState, openingPrayerAutoAssignState } from '../../states/congregation'; import { dbGetScheduleData } from '../../indexedDb/dbSchedule'; import { dbGetSourceMaterial } from '../../indexedDb/dbSourceMaterial'; import { dbSaveAss } from '../../indexedDb/dbAssignment'; @@ -26,11 +26,12 @@ const ScheduleAssignment = ({ edit }) => { const { t } = useTranslation('ui'); - const classCount = useRecoilValue(classCountState); - const theme = useTheme(); const lgDown = useMediaQuery(theme.breakpoints.down('lg'), { noSsr: true }); + const classCount = useRecoilValue(classCountState); + const autoAssignOpeningPrayer = useRecoilValue(openingPrayerAutoAssignState); + const [tgwTalkSrc, setTgwTalkSrc] = useState(''); const [bibleReadingSrc, setBibleReadingSrc] = useState(''); const [bibleReadingStudy, setBibleReadingStudy] = useState(''); @@ -286,6 +287,13 @@ const ScheduleAssignment = ({ edit }) => { await dbSaveAss(week, studentID, 'chairmanMM_A'); setChairmanA(studentName); setIsChairmanA(false); + + if (autoAssignOpeningPrayer) { + setIsOpeningPrayer(true); + await dbSaveAss(week, studentID, 'opening_prayer'); + setOpeningPrayer(studentName); + setIsOpeningPrayer(false); + } } if (assID === 19) { @@ -736,6 +744,7 @@ const ScheduleAssignment = ({ edit }) => { {/* LC1 */} {lcPart1Src !== '' && ( { {/* LC2 */} {lcCount > 1 && lcPart2Src !== '' && ( { const classCount = useRecoilValue(classCountState); + const [isLCNoAssign, setIsLCNoAssign] = useState(false); + const [displayPerson, setDisplayPerson] = useState(false); + const [displayCBSReader, setDisplayCBSReader] = useState(true); + const getContainerStyle = () => { if (student) { if (classCount === 1) return styles.studentPartWrapper1; @@ -95,6 +102,44 @@ const ScheduleRowAssignment = ({ return styles.studentContainer1; }; + useEffect(() => { + const verifyLCPart = async () => { + const noAssign = await checkLCAssignments(source); + setIsLCNoAssign(noAssign); + }; + + if (isLC) verifyLCPart(); + }, [isLC, source]); + + useEffect(() => { + if (assType) { + if (assType !== 105 && assType !== 106 && assType !== 107 && assType !== 117) { + setDisplayPerson(true); + return; + } + + setDisplayPerson(false); + } + + if (!assType) { + if (isLC) { + setDisplayPerson(!isLCNoAssign); + return; + } + + setDisplayPerson(true); + } + }, [assType, isLCNoAssign, isLC, assTypeName]); + + useEffect(() => { + const verifyCBSReader = async () => { + const noAssignCBSReader = await checkCBSReader(lcPart); + setDisplayCBSReader(!noAssignCBSReader); + }; + + if (cbs) verifyCBSReader(); + }, [cbs, lcPart]); + return ( )} - {(!assType || (assType && assType !== 105 && assType !== 106 && assType !== 107 && assType !== 117)) && ( + {displayPerson && ( {(edit || personA) && ( )} - {((classCount === 2 && weekType === 1 && student) || cbs) && ( + {((classCount === 2 && weekType === 1 && student) || (cbs && displayCBSReader)) && ( <> {(edit || personB) && ( { const [classCount, setClassCount] = useRecoilState(classCountState); const [meetingDay, setMeetingDay] = useRecoilState(meetingDayState); const [meetingTime, setMeetingTime] = useRecoilState(meetingTimeState); + const [autoAssignOpeningPrayer, setAutoAssignOpeningPrayer] = useRecoilState(openingPrayerAutoAssignState); const congName = useRecoilValue(congNameState); const congNumber = useRecoilValue(congNumberState); @@ -34,6 +38,7 @@ const BasicSettings = () => { const [tempMeetingTime, setTempMeetingTime] = useState(meetingTime); const [coName, setCoName] = useState(''); const [coDisplayName, setCoDisplayName] = useState(''); + const [tmpAutoAssignOpeningPrayer, setTmpAutoAssignOpeningPrayer] = useState(autoAssignOpeningPrayer); const handleMeetingDayChange = async (e) => { setTempMeetingDay(e.target.value); @@ -70,6 +75,12 @@ const BasicSettings = () => { await dbUpdateAppSettings({ co_displayName: value }); }; + const handleSwitchAutoAssignPrayer = async (value) => { + setTmpAutoAssignOpeningPrayer(value); + await dbUpdateAppSettings({ opening_prayer_autoAssign: value }); + setAutoAssignOpeningPrayer(value); + }; + useEffect(() => { const getAppSettings = async () => { const settings = await dbGetAppSettings(); @@ -164,29 +175,45 @@ const BasicSettings = () => { - {t('circuitOverseer')} + + {t('scheduleSettings')} + + handleSwitchAutoAssignPrayer(e.target.checked)} + /> + } + label={t('autoAssignOpeningPrayer')} + /> + + - - handleChangeCOName(e.target.value)} - /> - handleChangeCODispName(e.target.value)} - /> + + {t('circuitOverseer')} + + handleChangeCOName(e.target.value)} + /> + handleChangeCODispName(e.target.value)} + /> + diff --git a/src/indexedDb/dbAssignment.js b/src/indexedDb/dbAssignment.js index a48384f60f..be4171b5bf 100644 --- a/src/indexedDb/dbAssignment.js +++ b/src/indexedDb/dbAssignment.js @@ -554,9 +554,6 @@ export const dbRefreshStudentHistory = async (varPrev, varNew) => { const students = await dbGetStudentsMini(); await promiseSetRecoil(allStudentsState, students); await promiseSetRecoil(filteredStudentsState, students); - - const history = await dbHistoryAssignment(); - await promiseSetRecoil(studentsAssignmentHistoryState, history); } } } diff --git a/src/indexedDb/dbSchedule.js b/src/indexedDb/dbSchedule.js index bc04441c8e..c1cf05e943 100644 --- a/src/indexedDb/dbSchedule.js +++ b/src/indexedDb/dbSchedule.js @@ -6,6 +6,8 @@ import { monthNamesState, shortDateFormatState } from '../states/main'; import { yearsListState } from '../states/sourceMaterial'; import { dbGetStudentByUid } from './dbPersons'; import { + checkCBSReader, + checkLCAssignments, dbGetScheduleListByYear, dbGetSourceMaterial, dbGetSourceMaterialPocket, @@ -140,6 +142,7 @@ export const dbCountAssignmentsInfo = async (week) => { let assAssigned = 0; const classCount = await promiseGetRecoil(classCountState); + const schedData = await dbGetScheduleData(week); const sourceData = await dbGetSourceMaterial(week); @@ -255,7 +258,10 @@ export const dbCountAssignmentsInfo = async (week) => { } // LC Part 1 - assTotal = assTotal + 1; + const noAssignLC1 = await checkLCAssignments(sourceData.lcPart1_src); + if (!noAssignLC1) { + assTotal = assTotal + 1; + } if (schedData.lc_part1 && schedData.lc_part1 !== '') { assAssigned = assAssigned + 1; @@ -264,11 +270,14 @@ export const dbCountAssignmentsInfo = async (week) => { // LC Part 2 let cnLC2 = false; if (sourceData.lcCount_override === undefined && sourceData.lcCount === 2) { - cnLC2 = true; + const noAssignLC2 = await checkLCAssignments(sourceData.lcPart2_src); + cnLC2 = !noAssignLC2; } if (sourceData.lcCount_override !== undefined && sourceData.lcCount_override === 2) { - cnLC2 = true; + const noAssignLC2 = await checkLCAssignments(sourceData.lcPart2_src_override); + cnLC2 = !noAssignLC2; } + if (cnLC2) { assTotal = assTotal + 1; @@ -287,7 +296,10 @@ export const dbCountAssignmentsInfo = async (week) => { } // Reader - assTotal = assTotal + 1; + const noAssignCBSReader = await checkCBSReader(sourceData.cbs_src); + if (!noAssignCBSReader) { + assTotal = assTotal + 1; + } if (schedData.cbs_reader && schedData.cbs_reader !== '') { assAssigned = assAssigned + 1; diff --git a/src/indexedDb/dbSourceMaterial.js b/src/indexedDb/dbSourceMaterial.js index bfccaa14ff..4a591febd1 100644 --- a/src/indexedDb/dbSourceMaterial.js +++ b/src/indexedDb/dbSourceMaterial.js @@ -6,6 +6,7 @@ import { assTypeLocalState } from '../states/sourceMaterial'; import { dbHistoryAssignment, dbLastAssignment } from './dbAssignment'; import { allStudentsState, filteredStudentsState, studentsAssignmentHistoryState } from '../states/persons'; import { dbGetStudentsMini } from './dbPersons'; +import { getI18n } from 'react-i18next'; export const dbGetListWeekType = async () => { const weekTypeList = []; @@ -686,3 +687,45 @@ export const getOldestWeek = async () => { return appData[0].weekOf; }; + +export const checkLCAssignments = async (source) => { + const sourceLang = await promiseGetRecoil(sourceLangState); + + const { t } = getI18n(); + + const search = `(${t('lcNoAssignedVariations', { lng: sourceLang, ns: 'source' })})`; + const regex = new RegExp(search.toLowerCase()); + const array = regex.exec(source.toLowerCase()); + + return Array.isArray(array); +}; + +export const checkCBSReader = async (source) => { + const sourceLang = await promiseGetRecoil(sourceLangState); + + const { t } = getI18n(); + + let search = t('cbsLffWithPointsVariations', { lng: sourceLang, ns: 'source' }); + search = search.replaceAll('{{ lesson }}', '\\d+'); + search = search.replaceAll('{{ points }}', '(\\d+-\\d+|\\d+)'); + + let regex = new RegExp(search.toLowerCase()); + let array = regex.exec(source.toLowerCase()); + + if (Array.isArray(array)) { + let lffPoint = array[1] || array[2]; + lffPoint = +lffPoint.charAt(0); + + return lffPoint !== 1; + } + + if (!Array.isArray(array)) { + search = t('cbsLffSectionOnlyVariations', { lng: sourceLang, ns: 'source' }); + regex = new RegExp(search); + array = regex.exec(source); + + return Array.isArray(array); + } + + return false; +}; diff --git a/src/indexedDb/mainDb.js b/src/indexedDb/mainDb.js index 9533202b18..111b5a71cb 100644 --- a/src/indexedDb/mainDb.js +++ b/src/indexedDb/mainDb.js @@ -52,6 +52,10 @@ appDb.version(6).stores({ persons: '&person_uid, person_name, person_displayName, isMale, isFemale, isUnavailable, lastAssignment, assignments, timeAway, isMoved, isDisqualified, changes', }); +appDb.version(7).stores({ + app_settings: + '++id, username, local_uid, source_lang, cong_number, cong_name, cong_role, class_count, meeting_day, meeting_time, isScheduleConverted, isCongVerified, isAssignmentsConverted, isCongUpdated2, pocket_members, user_avatar, account_version, co_name, co_displayName, personAssignmentsConverted, autoBackup, autoBackup_interval, schedule_useFullname, account_type, opening_prayer_autoAssign', +}); appDb.on('populate', function () { appDb.app_settings.add({ @@ -70,6 +74,7 @@ appDb.on('populate', function () { account_version: 'v2', personAssignmentsConverted: true, schedule_useFullname: false, + opening_prayer_autoAssign: false, }); }); diff --git a/src/locales/en/source.json b/src/locales/en/source.json index c8e84cbd81..8622e53494 100644 --- a/src/locales/en/source.json +++ b/src/locales/en/source.json @@ -51,5 +51,8 @@ "tgwTalk": "Talk 10 min.", "lcPart": "Living Parts", "initialCallVariations": "0", - "returnVisitVariations": "0" + "returnVisitVariations": "0", + "lcNoAssignedVariations": "Organizational Accomplishments", + "cbsLffWithPointsVariations": "lff lesson {{ lesson }} points {{ points }}|lff lesson {{ lesson }} point {{ points }}", + "cbsLffSectionOnlyVariations": "lff section" } diff --git a/src/locales/en/ui.json b/src/locales/en/ui.json index 61253e197d..34a419ff7c 100644 --- a/src/locales/en/ui.json +++ b/src/locales/en/ui.json @@ -463,5 +463,7 @@ "noSchedules": "Please ask your congregation elders to publish the meeting schedule first", "noSchedule": "There is no schedule for this week", "downloadOldSourceMaterials": "Check this option if you want to download old source materials", - "mwbIssueMonth": "Issue month" + "mwbIssueMonth": "Issue month", + "scheduleSettings": "Schedule settings", + "autoAssignOpeningPrayer": "Auto-assign Chairman for Opening Prayer" } diff --git a/src/states/congregation.js b/src/states/congregation.js index 1b4c3d0bdb..514ec55f39 100644 --- a/src/states/congregation.js +++ b/src/states/congregation.js @@ -94,3 +94,8 @@ export const pocketLocalIDState = atom({ key: 'pocketLocalID', default: '', }); + +export const openingPrayerAutoAssignState = atom({ + key: 'openingPrayerAutoAssign', + default: false, +}); diff --git a/src/utils/app.js b/src/utils/app.js index 7af0439f16..a575df5d09 100644 --- a/src/utils/app.js +++ b/src/utils/app.js @@ -13,6 +13,7 @@ import { congNumberState, meetingDayState, meetingTimeState, + openingPrayerAutoAssignState, usernameState, } from '../states/congregation'; import { @@ -49,6 +50,7 @@ export const loadApp = async () => { autoBackup_interval, schedule_useFullname, account_type, + opening_prayer_autoAssign, } = await dbGetAppSettings(); backupWorkerInstance.setBackupInterval(autoBackup_interval); @@ -81,6 +83,7 @@ export const loadApp = async () => { await promiseSetRecoil(appLangState, app_lang); await promiseSetRecoil(sourceLangState, source_lang || app_lang); await promiseSetRecoil(scheduleUseFullnameState, schedule_useFullname || false); + await promiseSetRecoil(openingPrayerAutoAssignState, opening_prayer_autoAssign || false); if (source_lang === undefined) await dbUpdateAppSettings({ source_lang: app_lang });