diff --git a/database/schedule.ts b/database/schedule.ts index 69f7feb..b169a95 100644 --- a/database/schedule.ts +++ b/database/schedule.ts @@ -15,6 +15,7 @@ import { } from 'types' const ASSIGNEE_FIELDS = ['assignee', 'assistant', 'assignee2', 'assistant2'] as const +const SECOND_SCHOOL_ASSIGNEE_FIELDS = ['assignee2', 'assistant2'] as const type CollScheduleWeek = MongoInterface @@ -176,10 +177,13 @@ export const updateWeekType = async (weekID: string, language: Languages, type: break case WEEK_TYPES.coVisit.value: - for (const assignmentName of ['congregationBibleStudy', 'reader'] as const) { + for (const assignmentName of ['congregationBibleStudy', 'reader', 'bibleReading', 'studentTalk1', 'studentTalk2', 'studentTalk3', 'studentTalk4'] as const) { const assignment = week.assignments[assignmentName] if (assignment) { - for (const field of ASSIGNEE_FIELDS) { + const fieldsToCheck = ['bibleReading', 'studentTalk1', 'studentTalk2', 'studentTalk3', 'studentTalk4'].includes(assignmentName) + ? SECOND_SCHOOL_ASSIGNEE_FIELDS + : ASSIGNEE_FIELDS + for (const field of fieldsToCheck) { const memberID = assignment[field] if (memberID) { const member = await removeAssignment(memberID, { type: assignment.type, date: baseWeek.date }) diff --git a/database/setup.ts b/database/setup.ts index 608cea6..0468f7d 100644 --- a/database/setup.ts +++ b/database/setup.ts @@ -3,11 +3,14 @@ import { MongoClient } from 'mongodb' dotenv.config() -const { MONGODB_URI = '', MONGODB_NAME = '' } = process.env +const { MONGODB_URI = '' } = process.env const connectionOptions = { useNewUrlParser: true, validateOptions: true } export default MongoClient.connect(MONGODB_URI, connectionOptions) - .then((client: MongoClient) => client.db(MONGODB_NAME)) + .then(async (client: MongoClient) => { + const { SETTINGS } = await import('../src/constants') + return client.db(SETTINGS.db) + }) diff --git a/package.json b/package.json index d43f86e..10cae8c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "oclm-planner", - "version": "1.1.0", + "version": "1.1.1", "private": true, "scripts": { "serve": "npm-run-all --parallel serve:**", diff --git a/sample.env b/sample.env index 1855f4b..d580433 100644 --- a/sample.env +++ b/sample.env @@ -1,6 +1,4 @@ MONGODB_URI=CONNECTION_URI -MONGODB_NAME=OCLM JWT_SECRET=SUPER_SECRET_PHRASE PASSWORD=LOGIN_PASSWORD -VUE_APP_LANGUAGES=en,tpo -VUE_APP_SCHOOLS=1 +VUE_APP_SLUG=SLUG diff --git a/src/components/Schedule/ScheduleAssignment.vue b/src/components/Schedule/ScheduleAssignment.vue index c9a443a..501b566 100644 --- a/src/components/Schedule/ScheduleAssignment.vue +++ b/src/components/Schedule/ScheduleAssignment.vue @@ -81,9 +81,11 @@ export default Vue.extend({ return ['initialCall', 'returnVisit', 'bibleStudy'].includes(details.type) }, hasSecondSchool (): boolean { - const { details } = this.assignment + const { details, coVisit } = this.assignment if (!details) return false - return SECOND_SCHOOL && ['initialCall', 'returnVisit', 'bibleStudy', 'studentTalk', 'bibleReading'].includes(details.type) + return SECOND_SCHOOL && + !coVisit && + ['initialCall', 'returnVisit', 'bibleStudy', 'studentTalk', 'bibleReading'].includes(details.type) } }, diff --git a/src/components/Schedule/ScheduleWeekView.vue b/src/components/Schedule/ScheduleWeekView.vue index 8434114..3838463 100644 --- a/src/components/Schedule/ScheduleWeekView.vue +++ b/src/components/Schedule/ScheduleWeekView.vue @@ -431,6 +431,7 @@ export default class ScheduleWeekView extends Vue { } get assignments (): ScheduleWeekViewAssignmentMap { + const { coVisit } = this const { assignments } = this.week const assignmentRefs: { name: Assignments, displayName: string }[] = [ { name: 'chairman', displayName: 'Chairman' }, @@ -452,14 +453,14 @@ export default class ScheduleWeekView extends Vue { const assignment = assignments[name] const inherit = !!(assignment && assignment.inherit) const details = inherit ? this.localWeek.en.assignments[name] : assignment - return Object.assign(acc, { - [name]: { - name, - displayName, - inherit, - details - } - }) + const value: IScheduleWeekViewAssignment = { + name, + displayName, + inherit, + coVisit, + details + } + return Object.assign(acc, { [name]: value }) }, {}) as ScheduleWeekViewAssignmentMap } @@ -491,7 +492,9 @@ export default class ScheduleWeekView extends Vue { } get hasSecondSchool (): boolean { - return SECOND_SCHOOL && ['initialCall', 'returnVisit', 'bibleStudy', 'studentTalk', 'bibleReading'].includes(this.editAssignment.type) + return SECOND_SCHOOL && + !this.coVisit && + ['initialCall', 'returnVisit', 'bibleStudy', 'studentTalk', 'bibleReading'].includes(this.editAssignment.type) } // Methods diff --git a/src/constants.ts b/src/constants.ts index 977b749..a84f672 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -1,4 +1,7 @@ -import { Languages } from 'types' +import * as settings from './settings' +import { Languages, Slug } from 'types' + +export const SETTINGS = settings[process.env.VUE_APP_SLUG as Slug] // TODO: Probably just worth having one map of talks with all their information export const ASSIGNMENT_TYPE_MAP = { @@ -52,14 +55,13 @@ export const SUPPORTED_LANGUAGES = [ { text: 'Portuguese', value: 'tpo' } ] as const -export const USED_LANGUAGES = (process.env.VUE_APP_LANGUAGES || 'en') - .split(',') +export const USED_LANGUAGES = SETTINGS.languages .reduce((acc: { text: string, value: Languages }[], l) => { const lang = SUPPORTED_LANGUAGES.find(s => s.value === l) return lang ? acc.concat(lang) : acc }, []) -export const SECOND_SCHOOL = Number(process.env.VUE_APP_SCHOOLS || 1) > 1 +export const SECOND_SCHOOL = SETTINGS.schools > 1 export const WEEK_TYPES = { normal: { label: 'Normal', value: 0 }, diff --git a/src/plugins/pdfMake.ts b/src/plugins/pdfMake.ts index 72587b4..c1171cb 100644 --- a/src/plugins/pdfMake.ts +++ b/src/plugins/pdfMake.ts @@ -2,7 +2,7 @@ import pdfMake, { Content, CurrentNode, TDocumentDefinitions } from 'pdfmake/bui import pdfFonts from 'pdfmake/build/vfs_fonts' import { congregationModule, scheduleModule } from '@/store' -import { COLORS, WEEK_TYPES, SECOND_SCHOOL } from '@/constants' +import { COLORS, WEEK_TYPES, SECOND_SCHOOL, SETTINGS } from '@/constants' import { IScheduleTranslationMap, IAssignmentTranslationMap, @@ -22,7 +22,6 @@ const TPO_MONTHS = ['Jan', 'Fev', 'Mar', 'Abr', 'Mai', 'Jun', 'Jul', 'Ago', 'Set const SCHEDULE_TRANSLATIONS: { [key in Languages]: IScheduleTranslationMap } = { en: { startTime: '7:00', - group: 'CANTON CONGREGATION', header: 'Our Christian Life & Ministry Schedule', week: 'WEEK', weeks: 'WEEKS', @@ -50,7 +49,6 @@ const SCHEDULE_TRANSLATIONS: { [key in Languages]: IScheduleTranslationMap } = { }, tpo: { startTime: '19:00', - group: 'GROUP PORTUGUÊS', header: 'Programação de reunião de semana', week: 'SEMANA', weeks: 'SEMANAS', @@ -186,11 +184,11 @@ function getAssignmentTitle (assignment: IScheduleAssignment): string { return `${title} (${time})` } -function getScheduleAssignees (assignment?: IScheduleAssignment): string { +function getScheduleAssignees (assignment: IScheduleAssignment, coVisit: boolean): string { if (!assignment) return '' if (assignment.stream) return '(Video Stream)' const { type, assignee, assistant, assignee2, assistant2 } = assignment - if (SECOND_SCHOOL && ['initialCall', 'returnVisit', 'bibleStudy', 'studentTalk', 'bibleReading'].includes(type)) { + if (SECOND_SCHOOL && !coVisit && ['initialCall', 'returnVisit', 'bibleStudy', 'studentTalk', 'bibleReading'].includes(type)) { if (['initialCall', 'returnVisit', 'bibleStudy'].includes(type)) { return getAssigneeName(assignee, '-', true) + ' & ' + getAssigneeName(assistant, '-', true) + ' | ' + getAssigneeName(assignee2, '-', true) + ' & ' + getAssigneeName(assistant2, '-', true) } else { @@ -300,7 +298,7 @@ export const generateSchedule: PDFGenerator = function (weeks, month) { stack: [ { columns: [ - { text: translation.group, width: 160, margin: [0, 8, 0, 0], bold: true }, + { text: SETTINGS.displayName.toUpperCase(), width: 160, margin: [0, 8, 0, 0], bold: true }, { text: translation.header, alignment: 'right', fontSize: 17, bold: true } ] } @@ -344,6 +342,8 @@ export const generateSchedule: PDFGenerator = function (weeks, month) { // If no assignments & not a special week then this isn't created if (!assignments) throw new Error('Week not created for the selected language') + const coVisit = type === WEEK_TYPES.coVisit.value + // Extract assignments from the correct language const baseAssignments = baseWeek.en.assignments const assignmentMap = ((Object.entries(assignments) as unknown) as [keyof IScheduleWeekAssignments, IScheduleAssignment][]) @@ -380,17 +380,17 @@ export const generateSchedule: PDFGenerator = function (weeks, month) { // Introduction Section stack.push(createScheduleTable(COLORS.TREASURES, [ - [setTime(translation.startTime), songs[0], translation.prayer + ':', getScheduleAssignees(openingPrayer), addTime(5), openingPrayer.inherit], - [timer, translation.openingComments + ' (3 min.)', translation.chairman + ':', getScheduleAssignees(chairman), addTime(3), chairman.inherit] + [setTime(translation.startTime), songs[0], translation.prayer + ':', getScheduleAssignees(openingPrayer, coVisit), addTime(5), openingPrayer.inherit], + [timer, translation.openingComments + ' (3 min.)', translation.chairman + ':', getScheduleAssignees(chairman, coVisit), addTime(3), chairman.inherit] ])) // TREASURES Section stack.push(createScheduleSubheader(translation.treasures, COLORS.TREASURES)) const bibleReadingTitle = `${translation.bibleReading} (${bibleReading.time}): ${bibleReading.title}` stack.push(createScheduleTable(COLORS.TREASURES, [ - [timer, getAssignmentTitle(highlights), null, getScheduleAssignees(highlights), addTime(highlights.time), highlights.inherit], - [timer, translation.gems + ' (10 min.)', null, getScheduleAssignees(gems), addTime(gems.time), gems.inherit], - [timer, bibleReadingTitle, null, getScheduleAssignees(bibleReading), addTime(bibleReading.time), bibleReading.inherit, true] + [timer, getAssignmentTitle(highlights), null, getScheduleAssignees(highlights, coVisit), addTime(highlights.time), highlights.inherit], + [timer, translation.gems + ' (10 min.)', null, getScheduleAssignees(gems, coVisit), addTime(gems.time), gems.inherit], + [timer, bibleReadingTitle, null, getScheduleAssignees(bibleReading, coVisit), addTime(bibleReading.time), bibleReading.inherit, true] ])) // MINISTRY Section @@ -406,7 +406,7 @@ export const generateSchedule: PDFGenerator = function (weeks, month) { let assigneeTitle = `${translation.student}/${translation.assistant}:` if (studentTalk.type === 'ministryVideo') assigneeTitle = '' if (studentTalk.type === 'studentTalk') assigneeTitle = translation.student + ':' - ministryTableRows.push([timer, getAssignmentTitle(studentTalk), assigneeTitle, getScheduleAssignees(studentTalk), addTime(studentTalk.time), studentTalk.inherit, true]) + ministryTableRows.push([timer, getAssignmentTitle(studentTalk), assigneeTitle, getScheduleAssignees(studentTalk, coVisit), addTime(studentTalk.time), studentTalk.inherit, true]) } stack.push(createScheduleTable(COLORS.MINISTRY, ministryTableRows)) @@ -415,26 +415,26 @@ export const generateSchedule: PDFGenerator = function (weeks, month) { setTime(translation.startTime) const livingTableRows: ScheduleTableRow[] = [ [addTime(47), songs[1], null, null, addTime(5), chairman.inherit], - [timer, getAssignmentTitle(serviceTalk1), null, getScheduleAssignees(serviceTalk1), addTime(serviceTalk1.time), serviceTalk1.inherit], + [timer, getAssignmentTitle(serviceTalk1), null, getScheduleAssignees(serviceTalk1, coVisit), addTime(serviceTalk1.time), serviceTalk1.inherit], null ] - if (serviceTalk2) livingTableRows[2] = [timer, getAssignmentTitle(serviceTalk2), null, getScheduleAssignees(serviceTalk2), addTime(serviceTalk2.time), serviceTalk2.inherit] - if (type === WEEK_TYPES.coVisit.value) { + if (serviceTalk2) livingTableRows[2] = [timer, getAssignmentTitle(serviceTalk2), null, getScheduleAssignees(serviceTalk2, coVisit), addTime(serviceTalk2.time), serviceTalk2.inherit] + if (coVisit) { livingTableRows.push( - [timer, translation.review + ' (3 min.)', translation.chairman + ':', getScheduleAssignees(chairman), addTime(3), chairman.inherit], + [timer, translation.review + ' (3 min.)', translation.chairman + ':', getScheduleAssignees(chairman, coVisit), addTime(3), chairman.inherit], [timer, coTitle + ' (30 min.)', translation.co + ':', coName, addTime(30), true], - [timer, songs[2], translation.prayer + ':', getScheduleAssignees(closingPrayer), addTime(5), closingPrayer.inherit] + [timer, songs[2], translation.prayer + ':', getScheduleAssignees(closingPrayer, coVisit), addTime(5), closingPrayer.inherit] ) } else { livingTableRows.push( - [timer, translation.cbs + ' (30 min.)', translation.conductor + ':', getScheduleAssignees(congregationBibleStudy), addTime(30), congregationBibleStudy.inherit], - [null, congregationBibleStudy.title, translation.reader + ':', getScheduleAssignees(reader), null, reader.inherit], - [timer, translation.review + ' (3 min.)', translation.chairman + ':', getScheduleAssignees(chairman), addTime(3), chairman.inherit], - [timer, songs[2], translation.prayer + ':', getScheduleAssignees(closingPrayer), addTime(5), closingPrayer.inherit] + [timer, translation.cbs + ' (30 min.)', translation.conductor + ':', getScheduleAssignees(congregationBibleStudy, coVisit), addTime(30), congregationBibleStudy.inherit], + [null, congregationBibleStudy.title, translation.reader + ':', getScheduleAssignees(reader, coVisit), null, reader.inherit], + [timer, translation.review + ' (3 min.)', translation.chairman + ':', getScheduleAssignees(chairman, coVisit), addTime(3), chairman.inherit], + [timer, songs[2], translation.prayer + ':', getScheduleAssignees(closingPrayer, coVisit), addTime(5), closingPrayer.inherit] ) } const livingTable = createScheduleTable(COLORS.LIVING, livingTableRows) - if (type !== WEEK_TYPES.coVisit.value) { + if (!coVisit) { const coTalk = livingTable.table && livingTable.table.body && livingTable.table.body[3] && livingTable.table.body[3][1] if (!coTalk) throw new Error('Could not reformat according to CO week') Object.assign(coTalk, { rowSpan: 2 }) @@ -612,13 +612,14 @@ export const generateAssignmentSlips: PDFGenerator = function (weeks, month) { if (!week) throw new Error('Week not created for the selected language') const { type, assignments } = week if (type === WEEK_TYPES.assembly.value || type === WEEK_TYPES.memorial.value) continue + const coVisit = type === WEEK_TYPES.coVisit.value for (let i = 0; i <= 4; i++) { // treat index 0 as the bibleReading, else extract a student talk const index = i === 0 ? 'bibleReading' : 'studentTalk' + i as 'bibleReading' | 'studentTalk1' | 'studentTalk2' | 'studentTalk3' | 'studentTalk4' const talk: IScheduleAssignment | undefined = assignments[index] if (!talk || talk.inherit || !(VALID_TYPES.includes(talk.type))) continue slips.push(createSlip(translation, talk, false, date)) - if (SECOND_SCHOOL) slips.push(createSlip(translation, talk, true, date)) + if (SECOND_SCHOOL && !coVisit) slips.push(createSlip(translation, talk, true, date)) } } diff --git a/src/settings.ts b/src/settings.ts new file mode 100644 index 0000000..057f7a8 --- /dev/null +++ b/src/settings.ts @@ -0,0 +1,25 @@ +import { ISettings } from 'types' + +export const test: ISettings = { + slug: 'test', + db: 'test', + displayName: 'Test Congregatiom', + languages: ['en'], + schools: 2 +} + +export const canton: ISettings = { + slug: 'canton', + db: 'oclm', + displayName: 'Canton Congregation', + languages: ['en', 'tpo'], + schools: 1 +} + +export const barry: ISettings = { + slug: 'barry', + db: 'barry', + displayName: 'Barry Congregation', + languages: ['en'], + schools: 2 +} diff --git a/src/views/Congregation.vue b/src/views/Congregation.vue index f1582f1..09929bb 100644 --- a/src/views/Congregation.vue +++ b/src/views/Congregation.vue @@ -250,7 +250,7 @@ export default Vue.extend({ }, onEdit (member: ICongregationMember): void { this.editID = member._id - const { name, gender, appointment, languageGroup, school, show, privileges } = member + const { name, gender, appointment, languageGroup, school = null, show, privileges } = member const updateProperties: Partial = { name, gender, diff --git a/src/views/Home.vue b/src/views/Home.vue index 419e535..d1d7002 100644 --- a/src/views/Home.vue +++ b/src/views/Home.vue @@ -8,7 +8,7 @@ Click the navigation menu on the top left to login and navigate the site

Changelog

- + +

@@ -60,11 +61,31 @@ interface IChange { export default Vue.extend({ name: 'Home', + data: () => ({ + panel: [true] + }), + computed: { changes (): IChange[] { return [ { - version: '1.1', + version: '1.1.1', + date: '19 Oct 2019', + summary: 'Fix schedule & second school display preferences', + updates: [ + { title: 'Features', items: ['Exclude second school assignments on Circuit Overseer visits'] }, + { + title: 'Fixes', + items: [ + 'Use congregation display name rather than always showing Canton on the PDF', + 'Default school preference to Any when editing a member that did not previously set a preference' + ] + }, + { title: 'Developer', items: ['Use a settings file rather than multiple env variables'] } + ] + }, + { + version: '1.1.0', date: '15 Oct 2019', summary: 'Adds support for different types of congregations', updates: [ @@ -105,7 +126,7 @@ export default Vue.extend({ ] }, { - version: '1.0', + version: '1.0.0', date: '13 Feb 2019', summary: 'Initial release of OCLM Planner', updates: [ diff --git a/types/interfaces.d.ts b/types/interfaces.d.ts index 9d0e274..95a9800 100644 --- a/types/interfaces.d.ts +++ b/types/interfaces.d.ts @@ -45,6 +45,7 @@ export interface IScheduleWeekViewAssignment { name: Assignments displayName: string inherit: boolean + coVisit: boolean details?: IScheduleAssignment } @@ -69,7 +70,6 @@ export interface ICongregationMember { export interface IScheduleTranslationMap { startTime: string - group: string header: string week: string weeks: string @@ -122,3 +122,11 @@ export interface IAssignmentTranslationMap { note: { text: string, bold?: boolean, italics?: boolean }[] footer: string } + +export interface ISettings { + slug: string + db: string + displayName: string + languages: [Languages, ...Languages[]] + schools: 1 | 2 +} diff --git a/types/types.d.ts b/types/types.d.ts index 69429de..34de3c9 100644 --- a/types/types.d.ts +++ b/types/types.d.ts @@ -1,8 +1,10 @@ +import * as settings from '@/settings' import { GENDERS, APPOINTMENTS, SUPPORTED_LANGUAGES, PRIVILEGES, COLORS } from '@/constants' import { IScheduleWeekLanguage, IScheduleWeekAssignments } from './interfaces' import { TCreatedPdf } from 'pdfmake/build/pdfmake' import { ObjectID } from 'mongodb' +export type Slug = keyof typeof settings export type Genders = typeof GENDERS[number] export type Appointments = typeof APPOINTMENTS[number] export type Languages = typeof SUPPORTED_LANGUAGES[number]['value']