mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-10-21 22:46:32 +00:00
724c88c201
A mechanical prettier --write over server/src, server/tests, server/scripts and shared/src with the workspaces' .prettierrc; nothing but layout and import order changes, and every file keeps the same set of imports. shared is formatted throughout and its format baseline is empty. The server baseline keeps the 35 files that Prettier would grow past their lint:size limit (they need a split first, which is not a formatting change), and the generated entity files stay as their generator writes them.
132 lines
4.4 KiB
TypeScript
132 lines
4.4 KiB
TypeScript
import { Days } from '../../../src/db/entities/Days.entity';
|
|
import { ShareTokens } from '../../../src/db/entities/ShareTokens.entity';
|
|
import { TripMembers } from '../../../src/db/entities/TripMembers.entity';
|
|
import { Trips } from '../../../src/db/entities/Trips.entity';
|
|
import { inContext, nextSeq, type FactoryOrm } from './context';
|
|
import { createRow, findRows, insertRows } from './rows';
|
|
import type { EntityDTO } from '@mikro-orm/core';
|
|
|
|
export type TripRow = EntityDTO<Trips>;
|
|
export type DayRow = EntityDTO<Days>;
|
|
|
|
export interface TripOverrides {
|
|
title?: string;
|
|
description?: string | null;
|
|
start_date?: string | null;
|
|
end_date?: string | null;
|
|
currency?: string;
|
|
feed_token?: string | null;
|
|
is_archived?: number;
|
|
reminder_days?: number;
|
|
cover_image?: string | null;
|
|
}
|
|
|
|
/**
|
|
* The calendar dates from `start` to `end`, both included. Stepped in UTC: a
|
|
* date-only string parses as UTC midnight, and stepping local time would
|
|
* drop or repeat a day across a DST change.
|
|
*/
|
|
export function datesBetween(start: string, end: string): string[] {
|
|
const dates: string[] = [];
|
|
for (let d = new Date(start); d <= new Date(end); d.setUTCDate(d.getUTCDate() + 1)) {
|
|
dates.push(d.toISOString().slice(0, 10));
|
|
}
|
|
return dates;
|
|
}
|
|
|
|
/**
|
|
* A trip owned by `userId`. With both dates set it also gets one day per
|
|
* date, numbered from 1, as the trips service creates them.
|
|
*/
|
|
export async function makeTrip(orm: FactoryOrm, userId: number, overrides: TripOverrides = {}): Promise<TripRow> {
|
|
const trip = await createRow(orm, Trips, {
|
|
user: userId,
|
|
title: overrides.title ?? `Test Trip ${nextSeq('trip')}`,
|
|
description: overrides.description ?? null,
|
|
start_date: overrides.start_date ?? null,
|
|
end_date: overrides.end_date ?? null,
|
|
...(overrides.currency !== undefined ? { currency: overrides.currency } : {}),
|
|
...(overrides.feed_token !== undefined ? { feed_token: overrides.feed_token } : {}),
|
|
...(overrides.is_archived !== undefined ? { is_archived: overrides.is_archived } : {}),
|
|
...(overrides.reminder_days !== undefined ? { reminder_days: overrides.reminder_days } : {}),
|
|
...(overrides.cover_image !== undefined ? { cover_image: overrides.cover_image } : {}),
|
|
});
|
|
if (overrides.start_date && overrides.end_date) {
|
|
const dates = datesBetween(overrides.start_date, overrides.end_date);
|
|
await insertRows(
|
|
orm,
|
|
Days,
|
|
dates.map((date, i) => ({ trip: trip.id, day_number: i + 1, date })),
|
|
);
|
|
}
|
|
return trip;
|
|
}
|
|
|
|
/** One more day on the trip; `day_number` defaults to the next free one. */
|
|
export async function makeDay(
|
|
orm: FactoryOrm,
|
|
tripId: number,
|
|
overrides: { day_number?: number; date?: string | null; title?: string | null; notes?: string | null } = {},
|
|
): Promise<DayRow> {
|
|
const dayNumber =
|
|
overrides.day_number ??
|
|
(await inContext(orm, async (em) => {
|
|
const last = await em.findOne(
|
|
Days,
|
|
{ trip: tripId },
|
|
{ orderBy: { day_number: 'desc' }, disableIdentityMap: true },
|
|
);
|
|
return (last?.day_number ?? 0) + 1;
|
|
}));
|
|
return createRow(orm, Days, {
|
|
trip: tripId,
|
|
day_number: dayNumber,
|
|
date: overrides.date ?? null,
|
|
title: overrides.title ?? null,
|
|
notes: overrides.notes ?? null,
|
|
});
|
|
}
|
|
|
|
/** The trip's days in day order. */
|
|
export function readTripDays(orm: FactoryOrm, tripId: number): Promise<DayRow[]> {
|
|
return findRows(orm, Days, { trip: tripId }, { day_number: 'asc' });
|
|
}
|
|
|
|
/** Adds `userId` to the trip's members; a second call for the same pair is a no-op. */
|
|
export async function addTripMember(
|
|
orm: FactoryOrm,
|
|
tripId: number,
|
|
userId: number,
|
|
invitedBy: number | null = null,
|
|
): Promise<void> {
|
|
await inContext(orm, (em) => em.getRepository(TripMembers).addIgnoringConflict(tripId, userId, invitedBy));
|
|
}
|
|
|
|
/** A public share link for the trip, sharing what the overrides switch on. */
|
|
export function makeShareToken(
|
|
orm: FactoryOrm,
|
|
tripId: number,
|
|
createdBy: number,
|
|
overrides: Partial<
|
|
Pick<
|
|
EntityDTO<ShareTokens>,
|
|
| 'token'
|
|
| 'share_map'
|
|
| 'share_bookings'
|
|
| 'share_packing'
|
|
| 'share_budget'
|
|
| 'share_collab'
|
|
| 'share_travel_only'
|
|
| 'share_hide_images'
|
|
| 'expires_at'
|
|
>
|
|
> = {},
|
|
): Promise<EntityDTO<ShareTokens>> {
|
|
return createRow(orm, ShareTokens, {
|
|
trip: tripId,
|
|
createdByRef: createdBy,
|
|
token: overrides.token ?? `share-${nextSeq('share-token')}-${tripId}`,
|
|
...overrides,
|
|
});
|
|
}
|