feat: navigation and UX improvements complete
This commit is contained in:
@@ -11,8 +11,8 @@ export class UserPreferencesRepository {
|
||||
|
||||
async findByUserId(userId: string): Promise<UserPreferences | null> {
|
||||
const query = `
|
||||
SELECT id, user_id, unit_system, currency_code, time_zone, created_at, updated_at
|
||||
FROM user_preferences
|
||||
SELECT id, user_id, unit_system, currency_code, time_zone, dark_mode, created_at, updated_at
|
||||
FROM user_preferences
|
||||
WHERE user_id = $1
|
||||
`;
|
||||
|
||||
@@ -22,8 +22,8 @@ export class UserPreferencesRepository {
|
||||
|
||||
async create(data: CreateUserPreferencesRequest): Promise<UserPreferences> {
|
||||
const query = `
|
||||
INSERT INTO user_preferences (user_id, unit_system, currency_code, time_zone)
|
||||
VALUES ($1, $2, $3, $4)
|
||||
INSERT INTO user_preferences (user_id, unit_system, currency_code, time_zone, dark_mode)
|
||||
VALUES ($1, $2, $3, $4, $5)
|
||||
RETURNING *
|
||||
`;
|
||||
|
||||
@@ -31,7 +31,8 @@ export class UserPreferencesRepository {
|
||||
data.userId,
|
||||
data.unitSystem || 'imperial',
|
||||
data.currencyCode || 'USD',
|
||||
data.timeZone || 'UTC'
|
||||
data.timeZone || 'UTC',
|
||||
data.darkMode ?? null
|
||||
];
|
||||
|
||||
const result = await this.db.query(query, values);
|
||||
@@ -55,6 +56,10 @@ export class UserPreferencesRepository {
|
||||
fields.push(`time_zone = $${paramCount++}`);
|
||||
values.push(data.timeZone);
|
||||
}
|
||||
if (data.darkMode !== undefined) {
|
||||
fields.push(`dark_mode = $${paramCount++}`);
|
||||
values.push(data.darkMode);
|
||||
}
|
||||
|
||||
if (fields.length === 0) {
|
||||
return this.findByUserId(userId);
|
||||
@@ -90,6 +95,7 @@ export class UserPreferencesRepository {
|
||||
unitSystem: row.unit_system,
|
||||
currencyCode: row.currency_code || 'USD',
|
||||
timeZone: row.time_zone || 'UTC',
|
||||
darkMode: row.dark_mode,
|
||||
createdAt: row.created_at,
|
||||
updatedAt: row.updated_at,
|
||||
};
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
-- Migration: Add dark_mode column to user_preferences
|
||||
-- NULL = use system preference, TRUE = dark mode, FALSE = light mode
|
||||
|
||||
ALTER TABLE user_preferences
|
||||
ADD COLUMN IF NOT EXISTS dark_mode BOOLEAN DEFAULT NULL;
|
||||
|
||||
-- Add comment for documentation
|
||||
COMMENT ON COLUMN user_preferences.dark_mode IS 'User dark mode preference. NULL means use system preference.';
|
||||
@@ -11,6 +11,7 @@ export interface UserPreferences {
|
||||
unitSystem: UnitSystem;
|
||||
currencyCode: string;
|
||||
timeZone: string;
|
||||
darkMode: boolean | null;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
}
|
||||
@@ -20,12 +21,14 @@ export interface CreateUserPreferencesRequest {
|
||||
unitSystem?: UnitSystem;
|
||||
currencyCode?: string;
|
||||
timeZone?: string;
|
||||
darkMode?: boolean | null;
|
||||
}
|
||||
|
||||
export interface UpdateUserPreferencesRequest {
|
||||
unitSystem?: UnitSystem;
|
||||
currencyCode?: string;
|
||||
timeZone?: string;
|
||||
darkMode?: boolean | null;
|
||||
}
|
||||
|
||||
export interface UserPreferencesResponse {
|
||||
@@ -34,6 +37,7 @@ export interface UserPreferencesResponse {
|
||||
unitSystem: UnitSystem;
|
||||
currencyCode: string;
|
||||
timeZone: string;
|
||||
darkMode: boolean | null;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
}
|
||||
|
||||
@@ -37,6 +37,7 @@ export class UserPreferencesController {
|
||||
unitSystem: preferences.unitSystem,
|
||||
currencyCode: preferences.currencyCode,
|
||||
timeZone: preferences.timeZone,
|
||||
darkMode: preferences.darkMode,
|
||||
createdAt: preferences.createdAt,
|
||||
updatedAt: preferences.updatedAt,
|
||||
});
|
||||
@@ -55,7 +56,7 @@ export class UserPreferencesController {
|
||||
) {
|
||||
try {
|
||||
const userId = (request as any).user.sub;
|
||||
const { unitSystem, currencyCode, timeZone } = request.body;
|
||||
const { unitSystem, currencyCode, timeZone, darkMode } = request.body;
|
||||
|
||||
// Validate unitSystem if provided
|
||||
if (unitSystem && !['imperial', 'metric'].includes(unitSystem)) {
|
||||
@@ -73,6 +74,14 @@ export class UserPreferencesController {
|
||||
});
|
||||
}
|
||||
|
||||
// Validate darkMode if provided (must be boolean or null)
|
||||
if (darkMode !== undefined && darkMode !== null && typeof darkMode !== 'boolean') {
|
||||
return reply.code(400).send({
|
||||
error: 'Bad Request',
|
||||
message: 'darkMode must be a boolean or null',
|
||||
});
|
||||
}
|
||||
|
||||
// Check if preferences exist, create if not
|
||||
let preferences = await this.repository.findByUserId(userId);
|
||||
if (!preferences) {
|
||||
@@ -81,12 +90,14 @@ export class UserPreferencesController {
|
||||
unitSystem: unitSystem || 'imperial',
|
||||
currencyCode: currencyCode || 'USD',
|
||||
timeZone: timeZone || 'UTC',
|
||||
darkMode: darkMode,
|
||||
});
|
||||
} else {
|
||||
const updated = await this.repository.update(userId, {
|
||||
unitSystem,
|
||||
currencyCode,
|
||||
timeZone,
|
||||
darkMode,
|
||||
});
|
||||
if (updated) {
|
||||
preferences = updated;
|
||||
@@ -99,6 +110,7 @@ export class UserPreferencesController {
|
||||
unitSystem: preferences.unitSystem,
|
||||
currencyCode: preferences.currencyCode,
|
||||
timeZone: preferences.timeZone,
|
||||
darkMode: preferences.darkMode,
|
||||
createdAt: preferences.createdAt,
|
||||
updatedAt: preferences.updatedAt,
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user