update preview date
This commit is contained in:
@@ -1,8 +1,9 @@
|
||||
import { Module } from '@nestjs/common'
|
||||
import { ScheduleSchema } from './schedule.schema'
|
||||
import { ScheduleService } from './schedule.service'
|
||||
|
||||
@Module({
|
||||
providers: [ScheduleSchema],
|
||||
exports: [ScheduleSchema],
|
||||
providers: [ScheduleSchema, ScheduleService],
|
||||
exports: [ScheduleSchema, ScheduleService],
|
||||
})
|
||||
export class ScheduleModule {}
|
||||
|
||||
@@ -8,12 +8,39 @@ import {
|
||||
import { Builder } from '../Graphql/graphql.builder'
|
||||
import { PrismaService } from '../Prisma/prisma.service'
|
||||
import { ScheduleStatus } from '@prisma/client'
|
||||
import { ScheduleService } from './schedule.service'
|
||||
import { AppConfigService } from '../AppConfig/appconfig.service'
|
||||
|
||||
export type ScheduleConfigType =
|
||||
| {
|
||||
midDayBreakTimeStart?: string | null | undefined
|
||||
midDayBreakTimeEnd?: string | null | undefined
|
||||
slotDuration?: string | null | undefined
|
||||
slotBreakDuration?: string | null | undefined
|
||||
slotEndTime?: string | null | undefined
|
||||
slotStartTime?: string | null | undefined
|
||||
}
|
||||
| null
|
||||
| undefined
|
||||
|
||||
export type ScheduleSlotType = {
|
||||
slot: string
|
||||
start: string
|
||||
end: string
|
||||
}
|
||||
|
||||
export type PreviewScheduleType = {
|
||||
totalSlots: number
|
||||
slots: ScheduleSlotType[]
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
export class ScheduleSchema extends PothosSchema {
|
||||
constructor(
|
||||
@Inject(SchemaBuilderToken) private readonly builder: Builder,
|
||||
private readonly prisma: PrismaService,
|
||||
private readonly scheduleService: ScheduleService,
|
||||
private readonly appConfigService: AppConfigService,
|
||||
) {
|
||||
super()
|
||||
}
|
||||
@@ -53,6 +80,29 @@ export class ScheduleSchema extends PothosSchema {
|
||||
})
|
||||
}
|
||||
|
||||
@PothosRef()
|
||||
scheduleSlot() {
|
||||
return this.builder.simpleObject('ScheduleSlot', {
|
||||
fields: (t) => ({
|
||||
slot: t.string({}),
|
||||
start: t.string({}),
|
||||
end: t.string({}),
|
||||
}),
|
||||
})
|
||||
}
|
||||
|
||||
@PothosRef()
|
||||
previewSchedule() {
|
||||
return this.builder.simpleObject('PreviewSchedule', {
|
||||
fields: (t) => ({
|
||||
totalSlots: t.int(),
|
||||
slots: t.field({
|
||||
type: [this.scheduleSlot()],
|
||||
}),
|
||||
}),
|
||||
})
|
||||
}
|
||||
|
||||
@PothosRef()
|
||||
scheduleDate() {
|
||||
return this.builder.prismaObject('ScheduleDate', {
|
||||
@@ -79,6 +129,21 @@ export class ScheduleSchema extends PothosSchema {
|
||||
})
|
||||
}
|
||||
|
||||
@PothosRef()
|
||||
scheduleConfigInput() {
|
||||
return this.builder.inputType('ScheduleConfigInput', {
|
||||
description: 'A schedule config in the system.',
|
||||
fields: (t) => ({
|
||||
midDayBreakTimeStart: t.string(),
|
||||
midDayBreakTimeEnd: t.string(),
|
||||
slotDuration: t.string(),
|
||||
slotBreakDuration: t.string(),
|
||||
slotEndTime: t.string(),
|
||||
slotStartTime: t.string(),
|
||||
}),
|
||||
})
|
||||
}
|
||||
|
||||
@Pothos()
|
||||
init(): void {
|
||||
this.builder.queryFields((t) => ({
|
||||
@@ -109,6 +174,21 @@ export class ScheduleSchema extends PothosSchema {
|
||||
})
|
||||
},
|
||||
}),
|
||||
|
||||
adminPreviewSchedule: t.field({
|
||||
type: this.previewSchedule(),
|
||||
description: 'Preview a schedule for admin.',
|
||||
args: {
|
||||
scheduleConfig: t.arg({
|
||||
type: this.scheduleConfigInput(),
|
||||
}),
|
||||
},
|
||||
resolve: async (_parent, args, _context, _info) => {
|
||||
return await this.scheduleService.createSchedulePreview(
|
||||
args.scheduleConfig,
|
||||
)
|
||||
},
|
||||
}),
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,16 @@
|
||||
import * as DateTimeUtils from '../common/utils/datetime.utils'
|
||||
|
||||
import { Injectable } from '@nestjs/common'
|
||||
import { Injectable, Logger } from '@nestjs/common'
|
||||
import { PrismaService } from 'src/Prisma/prisma.service'
|
||||
import { Schedule } from '@prisma/client'
|
||||
|
||||
import { AppConfigService } from 'src/AppConfig/appconfig.service'
|
||||
import {
|
||||
PreviewScheduleType,
|
||||
ScheduleConfigType,
|
||||
ScheduleSlotType,
|
||||
} from './schedule.schema'
|
||||
import { Config } from '@prisma/client'
|
||||
import * as _ from 'lodash'
|
||||
|
||||
@Injectable()
|
||||
export class ScheduleService {
|
||||
@@ -13,10 +19,176 @@ export class ScheduleService {
|
||||
private readonly appConfigService: AppConfigService,
|
||||
) {}
|
||||
|
||||
async createSchedule(schedule: Schedule) {
|
||||
// get config
|
||||
const config = await this.appConfigService.getVisibleConfigs()
|
||||
console.log(config)
|
||||
async createSchedulePreview(
|
||||
scheduleConfig: ScheduleConfigType,
|
||||
): Promise<PreviewScheduleType> {
|
||||
const config: Config[] = await this.appConfigService.getVisibleConfigs()
|
||||
Logger.log(config)
|
||||
// process scheduleConfig input by filling with default values from config
|
||||
const scheduleConfigFilled = this.processScheduleConfig(
|
||||
scheduleConfig,
|
||||
config,
|
||||
)
|
||||
// generate Slot By config
|
||||
const slots = this.generateSlots(scheduleConfigFilled)
|
||||
|
||||
return {
|
||||
totalSlots: slots.length,
|
||||
slots: slots,
|
||||
}
|
||||
}
|
||||
|
||||
generateSlots(scheduleConfigFilled: ScheduleConfigType): ScheduleSlotType[] {
|
||||
Logger.log(`Generating slots with config: ${scheduleConfigFilled}`)
|
||||
const slots: ScheduleSlotType[] = []
|
||||
const numberOfSlots = this.calculateNumberOfSlots(
|
||||
// @ts-ignore
|
||||
scheduleConfigFilled?.slotStartTime,
|
||||
// @ts-ignore
|
||||
scheduleConfigFilled?.slotEndTime,
|
||||
// @ts-ignore
|
||||
scheduleConfigFilled?.slotDuration,
|
||||
// @ts-ignore
|
||||
scheduleConfigFilled?.slotBreakDuration,
|
||||
)
|
||||
for (let i = 1; i <= numberOfSlots; i++) {
|
||||
const { startTime, endTime } = this.getSlotStartAndEndTime(
|
||||
i,
|
||||
// @ts-ignore
|
||||
scheduleConfigFilled?.slotDuration,
|
||||
// @ts-ignore
|
||||
scheduleConfigFilled?.slotBreakDuration,
|
||||
// @ts-ignore
|
||||
scheduleConfigFilled?.slotStartTime,
|
||||
)
|
||||
// if the slot is not overlapping with mid day break time, add it to the slots
|
||||
if (
|
||||
!this.isOverLapping(
|
||||
startTime,
|
||||
endTime,
|
||||
this.getSpecificDateWithTime(
|
||||
// @ts-ignore
|
||||
scheduleConfigFilled?.midDayBreakTimeStart,
|
||||
),
|
||||
this.getSpecificDateWithTime(
|
||||
// @ts-ignore
|
||||
scheduleConfigFilled?.midDayBreakTimeEnd,
|
||||
),
|
||||
)
|
||||
) {
|
||||
slots.push({
|
||||
slot: i.toString(),
|
||||
start: startTime.toISOString(),
|
||||
end: endTime.toISOString(),
|
||||
})
|
||||
}
|
||||
}
|
||||
return slots
|
||||
}
|
||||
|
||||
isOverLapping(
|
||||
startTime1: Date,
|
||||
endTime1: Date,
|
||||
startTime2: Date,
|
||||
endTime2: Date,
|
||||
) {
|
||||
return (
|
||||
Math.max(startTime1.getTime(), startTime2.getTime()) <
|
||||
Math.min(endTime1.getTime(), endTime2.getTime())
|
||||
)
|
||||
}
|
||||
|
||||
calculateNumberOfSlots(
|
||||
startTime: string,
|
||||
endTime: string,
|
||||
slotDuration: string,
|
||||
slotBreakDuration: string,
|
||||
) {
|
||||
const startDate = new Date(startTime)
|
||||
const endDate = new Date(endTime)
|
||||
|
||||
const totalMinutes = (endDate.getTime() - startDate.getTime()) / (60 * 1000)
|
||||
const numberOfSlots = Math.floor(
|
||||
totalMinutes / (parseInt(slotDuration) + parseInt(slotBreakDuration)),
|
||||
)
|
||||
return numberOfSlots
|
||||
}
|
||||
|
||||
getSlotStartAndEndTime(
|
||||
slotNumber: number,
|
||||
slotDuration: string,
|
||||
slotBreakDuration: string,
|
||||
slotStartTime: string,
|
||||
) {
|
||||
const startTime = new Date(slotStartTime)
|
||||
startTime.setUTCMinutes(
|
||||
startTime.getUTCMinutes() +
|
||||
slotNumber * (parseInt(slotDuration) + parseInt(slotBreakDuration)),
|
||||
)
|
||||
const endTime = new Date(startTime)
|
||||
endTime.setUTCMinutes(endTime.getUTCMinutes() + parseInt(slotDuration))
|
||||
return { startTime, endTime }
|
||||
}
|
||||
|
||||
processScheduleConfig(
|
||||
scheduleConfig: ScheduleConfigType,
|
||||
config: Config[],
|
||||
): ScheduleConfigType {
|
||||
// if scheduleConfig is undefined, create a new object and seed all the values with default values from config
|
||||
if (scheduleConfig === undefined) {
|
||||
scheduleConfig = config.reduce((acc, curr) => {
|
||||
// biome-ignore lint/suspicious/noExplicitAny: <explanation>
|
||||
;(acc as any)[this.sneakyCaseToCamelCase(curr.key)] = curr.value
|
||||
return acc
|
||||
}, {})
|
||||
}
|
||||
// loop through scheduleConfig and fill with default values from config
|
||||
for (const key in scheduleConfig) {
|
||||
if (
|
||||
// biome-ignore lint/suspicious/noExplicitAny: <explanation>
|
||||
(scheduleConfig as any)[key] === undefined ||
|
||||
// biome-ignore lint/suspicious/noExplicitAny: <explanation>
|
||||
(scheduleConfig as any)[key] === null ||
|
||||
// biome-ignore lint/suspicious/noExplicitAny: <explanation>
|
||||
(scheduleConfig as any)[key] === ''
|
||||
) {
|
||||
// biome-ignore lint/suspicious/noExplicitAny: <explanation>
|
||||
;(scheduleConfig as any)[key] =
|
||||
// biome-ignore lint/suspicious/noExplicitAny: <explanation>
|
||||
config[this.camelCaseToUpperSneakyCase(key) as any]
|
||||
}
|
||||
}
|
||||
return scheduleConfig
|
||||
}
|
||||
|
||||
camelCaseToUpperSneakyCase(str: string) {
|
||||
return _.snakeCase(str).toUpperCase()
|
||||
}
|
||||
|
||||
sneakyCaseToCamelCase(str: string) {
|
||||
return _.camelCase(str.toLowerCase())
|
||||
}
|
||||
|
||||
getTodayWithTime(date: Date) {
|
||||
const today = new Date()
|
||||
today.setUTCHours(
|
||||
date.getUTCHours(),
|
||||
date.getUTCMinutes(),
|
||||
date.getUTCSeconds(),
|
||||
0,
|
||||
)
|
||||
return today
|
||||
}
|
||||
|
||||
getSpecificDateWithTime(date: Date) {
|
||||
const specificDate = new Date(date)
|
||||
date = new Date(date)
|
||||
specificDate.setUTCHours(
|
||||
date.getUTCHours(),
|
||||
date.getUTCMinutes(),
|
||||
date.getUTCSeconds(),
|
||||
0,
|
||||
)
|
||||
return specificDate
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user