Notification updates
This commit is contained in:
@@ -5,20 +5,61 @@ import type { MaintenanceRecord, MaintenanceSchedule, MaintenanceCategory } from
|
||||
export class MaintenanceRepository {
|
||||
constructor(private readonly db: Pool = pool) {}
|
||||
|
||||
// ========================
|
||||
// Row Mappers
|
||||
// ========================
|
||||
|
||||
private mapMaintenanceRecord(row: any): MaintenanceRecord {
|
||||
return {
|
||||
id: row.id,
|
||||
userId: row.user_id,
|
||||
vehicleId: row.vehicle_id,
|
||||
category: row.category,
|
||||
subtypes: row.subtypes,
|
||||
date: row.date,
|
||||
odometerReading: row.odometer_reading,
|
||||
cost: row.cost,
|
||||
shopName: row.shop_name,
|
||||
notes: row.notes,
|
||||
createdAt: row.created_at,
|
||||
updatedAt: row.updated_at
|
||||
};
|
||||
}
|
||||
|
||||
private mapMaintenanceSchedule(row: any): MaintenanceSchedule {
|
||||
return {
|
||||
id: row.id,
|
||||
userId: row.user_id,
|
||||
vehicleId: row.vehicle_id,
|
||||
category: row.category,
|
||||
subtypes: row.subtypes,
|
||||
intervalMonths: row.interval_months,
|
||||
intervalMiles: row.interval_miles,
|
||||
lastServiceDate: row.last_service_date,
|
||||
lastServiceMileage: row.last_service_mileage,
|
||||
nextDueDate: row.next_due_date,
|
||||
nextDueMileage: row.next_due_mileage,
|
||||
isActive: row.is_active,
|
||||
emailNotifications: row.email_notifications,
|
||||
createdAt: row.created_at,
|
||||
updatedAt: row.updated_at
|
||||
};
|
||||
}
|
||||
|
||||
// ========================
|
||||
// Maintenance Records
|
||||
// ========================
|
||||
|
||||
async insertRecord(record: {
|
||||
id: string;
|
||||
user_id: string;
|
||||
vehicle_id: string;
|
||||
userId: string;
|
||||
vehicleId: string;
|
||||
category: MaintenanceCategory;
|
||||
subtypes: string[];
|
||||
date: string;
|
||||
odometer_reading?: number | null;
|
||||
odometerReading?: number | null;
|
||||
cost?: number | null;
|
||||
shop_name?: string | null;
|
||||
shopName?: string | null;
|
||||
notes?: string | null;
|
||||
}): Promise<MaintenanceRecord> {
|
||||
const res = await this.db.query(
|
||||
@@ -28,18 +69,18 @@ export class MaintenanceRepository {
|
||||
RETURNING *`,
|
||||
[
|
||||
record.id,
|
||||
record.user_id,
|
||||
record.vehicle_id,
|
||||
record.userId,
|
||||
record.vehicleId,
|
||||
record.category,
|
||||
record.subtypes,
|
||||
record.date,
|
||||
record.odometer_reading ?? null,
|
||||
record.odometerReading ?? null,
|
||||
record.cost ?? null,
|
||||
record.shop_name ?? null,
|
||||
record.shopName ?? null,
|
||||
record.notes ?? null,
|
||||
]
|
||||
);
|
||||
return res.rows[0] as MaintenanceRecord;
|
||||
return this.mapMaintenanceRecord(res.rows[0]);
|
||||
}
|
||||
|
||||
async findRecordById(id: string, userId: string): Promise<MaintenanceRecord | null> {
|
||||
@@ -47,7 +88,7 @@ export class MaintenanceRepository {
|
||||
`SELECT * FROM maintenance_records WHERE id = $1 AND user_id = $2`,
|
||||
[id, userId]
|
||||
);
|
||||
return res.rows[0] || null;
|
||||
return res.rows[0] ? this.mapMaintenanceRecord(res.rows[0]) : null;
|
||||
}
|
||||
|
||||
async findRecordsByUserId(
|
||||
@@ -69,7 +110,7 @@ export class MaintenanceRepository {
|
||||
|
||||
const sql = `SELECT * FROM maintenance_records WHERE ${conds.join(' AND ')} ORDER BY date DESC`;
|
||||
const res = await this.db.query(sql, params);
|
||||
return res.rows as MaintenanceRecord[];
|
||||
return res.rows.map(row => this.mapMaintenanceRecord(row));
|
||||
}
|
||||
|
||||
async findRecordsByVehicleId(vehicleId: string, userId: string): Promise<MaintenanceRecord[]> {
|
||||
@@ -77,13 +118,13 @@ export class MaintenanceRepository {
|
||||
`SELECT * FROM maintenance_records WHERE vehicle_id = $1 AND user_id = $2 ORDER BY date DESC`,
|
||||
[vehicleId, userId]
|
||||
);
|
||||
return res.rows as MaintenanceRecord[];
|
||||
return res.rows.map(row => this.mapMaintenanceRecord(row));
|
||||
}
|
||||
|
||||
async updateRecord(
|
||||
id: string,
|
||||
userId: string,
|
||||
patch: Partial<Pick<MaintenanceRecord, 'category' | 'subtypes' | 'date' | 'odometer_reading' | 'cost' | 'shop_name' | 'notes'>>
|
||||
patch: Partial<Pick<MaintenanceRecord, 'category' | 'subtypes' | 'date' | 'odometerReading' | 'cost' | 'shopName' | 'notes'>>
|
||||
): Promise<MaintenanceRecord | null> {
|
||||
const fields: string[] = [];
|
||||
const params: any[] = [];
|
||||
@@ -101,17 +142,17 @@ export class MaintenanceRepository {
|
||||
fields.push(`date = $${i++}`);
|
||||
params.push(patch.date);
|
||||
}
|
||||
if (patch.odometer_reading !== undefined) {
|
||||
if (patch.odometerReading !== undefined) {
|
||||
fields.push(`odometer_reading = $${i++}`);
|
||||
params.push(patch.odometer_reading);
|
||||
params.push(patch.odometerReading);
|
||||
}
|
||||
if (patch.cost !== undefined) {
|
||||
fields.push(`cost = $${i++}`);
|
||||
params.push(patch.cost);
|
||||
}
|
||||
if (patch.shop_name !== undefined) {
|
||||
if (patch.shopName !== undefined) {
|
||||
fields.push(`shop_name = $${i++}`);
|
||||
params.push(patch.shop_name);
|
||||
params.push(patch.shopName);
|
||||
}
|
||||
if (patch.notes !== undefined) {
|
||||
fields.push(`notes = $${i++}`);
|
||||
@@ -123,7 +164,7 @@ export class MaintenanceRepository {
|
||||
params.push(id, userId);
|
||||
const sql = `UPDATE maintenance_records SET ${fields.join(', ')} WHERE id = $${i++} AND user_id = $${i++} RETURNING *`;
|
||||
const res = await this.db.query(sql, params);
|
||||
return res.rows[0] || null;
|
||||
return res.rows[0] ? this.mapMaintenanceRecord(res.rows[0]) : null;
|
||||
}
|
||||
|
||||
async deleteRecord(id: string, userId: string): Promise<void> {
|
||||
@@ -139,40 +180,42 @@ export class MaintenanceRepository {
|
||||
|
||||
async insertSchedule(schedule: {
|
||||
id: string;
|
||||
user_id: string;
|
||||
vehicle_id: string;
|
||||
userId: string;
|
||||
vehicleId: string;
|
||||
category: MaintenanceCategory;
|
||||
subtypes: string[];
|
||||
interval_months?: number | null;
|
||||
interval_miles?: number | null;
|
||||
last_service_date?: string | null;
|
||||
last_service_mileage?: number | null;
|
||||
next_due_date?: string | null;
|
||||
next_due_mileage?: number | null;
|
||||
is_active: boolean;
|
||||
intervalMonths?: number | null;
|
||||
intervalMiles?: number | null;
|
||||
lastServiceDate?: string | null;
|
||||
lastServiceMileage?: number | null;
|
||||
nextDueDate?: string | null;
|
||||
nextDueMileage?: number | null;
|
||||
isActive: boolean;
|
||||
emailNotifications?: boolean;
|
||||
}): Promise<MaintenanceSchedule> {
|
||||
const res = await this.db.query(
|
||||
`INSERT INTO maintenance_schedules (
|
||||
id, user_id, vehicle_id, category, subtypes, interval_months, interval_miles,
|
||||
last_service_date, last_service_mileage, next_due_date, next_due_mileage, is_active
|
||||
) VALUES ($1, $2, $3, $4, $5::text[], $6, $7, $8, $9, $10, $11, $12)
|
||||
last_service_date, last_service_mileage, next_due_date, next_due_mileage, is_active, email_notifications
|
||||
) VALUES ($1, $2, $3, $4, $5::text[], $6, $7, $8, $9, $10, $11, $12, $13)
|
||||
RETURNING *`,
|
||||
[
|
||||
schedule.id,
|
||||
schedule.user_id,
|
||||
schedule.vehicle_id,
|
||||
schedule.userId,
|
||||
schedule.vehicleId,
|
||||
schedule.category,
|
||||
schedule.subtypes,
|
||||
schedule.interval_months ?? null,
|
||||
schedule.interval_miles ?? null,
|
||||
schedule.last_service_date ?? null,
|
||||
schedule.last_service_mileage ?? null,
|
||||
schedule.next_due_date ?? null,
|
||||
schedule.next_due_mileage ?? null,
|
||||
schedule.is_active,
|
||||
schedule.intervalMonths ?? null,
|
||||
schedule.intervalMiles ?? null,
|
||||
schedule.lastServiceDate ?? null,
|
||||
schedule.lastServiceMileage ?? null,
|
||||
schedule.nextDueDate ?? null,
|
||||
schedule.nextDueMileage ?? null,
|
||||
schedule.isActive,
|
||||
schedule.emailNotifications ?? false,
|
||||
]
|
||||
);
|
||||
return res.rows[0] as MaintenanceSchedule;
|
||||
return this.mapMaintenanceSchedule(res.rows[0]);
|
||||
}
|
||||
|
||||
async findScheduleById(id: string, userId: string): Promise<MaintenanceSchedule | null> {
|
||||
@@ -180,7 +223,7 @@ export class MaintenanceRepository {
|
||||
`SELECT * FROM maintenance_schedules WHERE id = $1 AND user_id = $2`,
|
||||
[id, userId]
|
||||
);
|
||||
return res.rows[0] || null;
|
||||
return res.rows[0] ? this.mapMaintenanceSchedule(res.rows[0]) : null;
|
||||
}
|
||||
|
||||
async findSchedulesByVehicleId(vehicleId: string, userId: string): Promise<MaintenanceSchedule[]> {
|
||||
@@ -188,7 +231,7 @@ export class MaintenanceRepository {
|
||||
`SELECT * FROM maintenance_schedules WHERE vehicle_id = $1 AND user_id = $2 ORDER BY created_at DESC`,
|
||||
[vehicleId, userId]
|
||||
);
|
||||
return res.rows as MaintenanceSchedule[];
|
||||
return res.rows.map(row => this.mapMaintenanceSchedule(row));
|
||||
}
|
||||
|
||||
async findActiveSchedulesByVehicleId(vehicleId: string, userId: string): Promise<MaintenanceSchedule[]> {
|
||||
@@ -196,13 +239,13 @@ export class MaintenanceRepository {
|
||||
`SELECT * FROM maintenance_schedules WHERE vehicle_id = $1 AND user_id = $2 AND is_active = true ORDER BY created_at DESC`,
|
||||
[vehicleId, userId]
|
||||
);
|
||||
return res.rows as MaintenanceSchedule[];
|
||||
return res.rows.map(row => this.mapMaintenanceSchedule(row));
|
||||
}
|
||||
|
||||
async updateSchedule(
|
||||
id: string,
|
||||
userId: string,
|
||||
patch: Partial<Pick<MaintenanceSchedule, 'category' | 'subtypes' | 'interval_months' | 'interval_miles' | 'last_service_date' | 'last_service_mileage' | 'next_due_date' | 'next_due_mileage' | 'is_active'>>
|
||||
patch: Partial<Pick<MaintenanceSchedule, 'category' | 'subtypes' | 'intervalMonths' | 'intervalMiles' | 'lastServiceDate' | 'lastServiceMileage' | 'nextDueDate' | 'nextDueMileage' | 'isActive' | 'emailNotifications'>>
|
||||
): Promise<MaintenanceSchedule | null> {
|
||||
const fields: string[] = [];
|
||||
const params: any[] = [];
|
||||
@@ -216,33 +259,37 @@ export class MaintenanceRepository {
|
||||
fields.push(`subtypes = $${i++}::text[]`);
|
||||
params.push(patch.subtypes);
|
||||
}
|
||||
if (patch.interval_months !== undefined) {
|
||||
if (patch.intervalMonths !== undefined) {
|
||||
fields.push(`interval_months = $${i++}`);
|
||||
params.push(patch.interval_months);
|
||||
params.push(patch.intervalMonths);
|
||||
}
|
||||
if (patch.interval_miles !== undefined) {
|
||||
if (patch.intervalMiles !== undefined) {
|
||||
fields.push(`interval_miles = $${i++}`);
|
||||
params.push(patch.interval_miles);
|
||||
params.push(patch.intervalMiles);
|
||||
}
|
||||
if (patch.last_service_date !== undefined) {
|
||||
if (patch.lastServiceDate !== undefined) {
|
||||
fields.push(`last_service_date = $${i++}`);
|
||||
params.push(patch.last_service_date);
|
||||
params.push(patch.lastServiceDate);
|
||||
}
|
||||
if (patch.last_service_mileage !== undefined) {
|
||||
if (patch.lastServiceMileage !== undefined) {
|
||||
fields.push(`last_service_mileage = $${i++}`);
|
||||
params.push(patch.last_service_mileage);
|
||||
params.push(patch.lastServiceMileage);
|
||||
}
|
||||
if (patch.next_due_date !== undefined) {
|
||||
if (patch.nextDueDate !== undefined) {
|
||||
fields.push(`next_due_date = $${i++}`);
|
||||
params.push(patch.next_due_date);
|
||||
params.push(patch.nextDueDate);
|
||||
}
|
||||
if (patch.next_due_mileage !== undefined) {
|
||||
if (patch.nextDueMileage !== undefined) {
|
||||
fields.push(`next_due_mileage = $${i++}`);
|
||||
params.push(patch.next_due_mileage);
|
||||
params.push(patch.nextDueMileage);
|
||||
}
|
||||
if (patch.is_active !== undefined) {
|
||||
if (patch.isActive !== undefined) {
|
||||
fields.push(`is_active = $${i++}`);
|
||||
params.push(patch.is_active);
|
||||
params.push(patch.isActive);
|
||||
}
|
||||
if (patch.emailNotifications !== undefined) {
|
||||
fields.push(`email_notifications = $${i++}`);
|
||||
params.push(patch.emailNotifications);
|
||||
}
|
||||
|
||||
if (!fields.length) return this.findScheduleById(id, userId);
|
||||
@@ -250,7 +297,7 @@ export class MaintenanceRepository {
|
||||
params.push(id, userId);
|
||||
const sql = `UPDATE maintenance_schedules SET ${fields.join(', ')} WHERE id = $${i++} AND user_id = $${i++} RETURNING *`;
|
||||
const res = await this.db.query(sql, params);
|
||||
return res.rows[0] || null;
|
||||
return res.rows[0] ? this.mapMaintenanceSchedule(res.rows[0]) : null;
|
||||
}
|
||||
|
||||
async deleteSchedule(id: string, userId: string): Promise<void> {
|
||||
|
||||
Reference in New Issue
Block a user