Portal: 12-hour schedule times and dynamicAudio default on
Use TimeInput for Block start/end and show the day timeline axis with AM/PM, so no 24-hour time is displayed in the schedule UI. New Blocks now default dynamicAudio to true in the modal and server-side when the field is absent; existing stored Blocks are untouched.
This commit is contained in:
@@ -90,7 +90,7 @@ describe('createBlock', () => {
|
||||
scheduleId: 's1',
|
||||
startMinutes: validInput.startMinutes,
|
||||
endMinutes: validInput.endMinutes,
|
||||
dynamicAudio: false,
|
||||
dynamicAudio: true,
|
||||
proclamations: {
|
||||
create: [
|
||||
{ proclamationId: 'p1', sortOrder: 0 },
|
||||
@@ -101,6 +101,32 @@ describe('createBlock', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('defaults dynamic audio on when the field is absent', async () => {
|
||||
blockFindMany.mockResolvedValue([]);
|
||||
blockCreate.mockResolvedValue({ id: 'new-block' });
|
||||
|
||||
await createBlock('u1', validInput);
|
||||
|
||||
expect(blockCreate).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
data: expect.objectContaining({ dynamicAudio: true })
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
it('persists dynamic audio off when the field is explicitly false', async () => {
|
||||
blockFindMany.mockResolvedValue([]);
|
||||
blockCreate.mockResolvedValue({ id: 'new-block' });
|
||||
|
||||
await createBlock('u1', { ...validInput, dynamicAudio: false });
|
||||
|
||||
expect(blockCreate).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
data: expect.objectContaining({ dynamicAudio: false })
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
it('persists the dynamic audio flag', async () => {
|
||||
blockFindMany.mockResolvedValue([]);
|
||||
blockCreate.mockResolvedValue({ id: 'new-block' });
|
||||
@@ -168,7 +194,7 @@ describe('updateBlock', () => {
|
||||
data: {
|
||||
startMinutes: validInput.startMinutes,
|
||||
endMinutes: validInput.endMinutes,
|
||||
dynamicAudio: false,
|
||||
dynamicAudio: true,
|
||||
proclamations: {
|
||||
deleteMany: {},
|
||||
create: [{ proclamationId: 'p1', sortOrder: 0 }]
|
||||
|
||||
@@ -25,6 +25,14 @@ function uniqueIds(ids: string[]): string[] {
|
||||
return [...new Set(ids.filter((id) => typeof id === 'string' && id.length > 0))];
|
||||
}
|
||||
|
||||
/**
|
||||
* New Blocks default `dynamicAudio` to true when the field is absent. Existing
|
||||
* stored Blocks are never rewritten by this default.
|
||||
*/
|
||||
function dynamicAudioOrDefault(input: BlockInput): boolean {
|
||||
return input.dynamicAudio !== false;
|
||||
}
|
||||
|
||||
/** Ensure the user has a Schedule row, creating the singleton on first use. */
|
||||
export async function getOrCreateSchedule(userId: string) {
|
||||
const existing = await prisma.schedule.findUnique({ where: { userId } });
|
||||
@@ -67,7 +75,7 @@ export async function createBlock(userId: string, input: BlockInput): Promise<Bl
|
||||
scheduleId: schedule.id,
|
||||
startMinutes: input.startMinutes,
|
||||
endMinutes: input.endMinutes,
|
||||
dynamicAudio: input.dynamicAudio === true,
|
||||
dynamicAudio: dynamicAudioOrDefault(input),
|
||||
proclamations: {
|
||||
create: proclamationIds.map((proclamationId, index) => ({
|
||||
proclamationId,
|
||||
@@ -105,7 +113,7 @@ export async function updateBlock(
|
||||
data: {
|
||||
startMinutes: input.startMinutes,
|
||||
endMinutes: input.endMinutes,
|
||||
dynamicAudio: input.dynamicAudio === true,
|
||||
dynamicAudio: dynamicAudioOrDefault(input),
|
||||
proclamations: {
|
||||
deleteMany: {},
|
||||
create: proclamationIds.map((proclamationId, index) => ({
|
||||
|
||||
Reference in New Issue
Block a user