Refactor Docker setup for frontend-only builds by removing server-side API files, creating mock APIs, and updating health check notes. Adjusted Vite configuration for browser compatibility and refined API handling in various components to improve user experience and maintainability.
This commit is contained in:
@ -23,7 +23,7 @@ export interface AnalyticsFilters {
|
||||
// Track an analytics event
|
||||
export async function trackEvent(data: TrackEventData) {
|
||||
try {
|
||||
const eventRecord = await db.insert(scriptAnalytics).values({
|
||||
await db.insert(scriptAnalytics).values({
|
||||
id: generateId(),
|
||||
scriptId: data.scriptId,
|
||||
eventType: data.eventType,
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { db } from '@/lib/db';
|
||||
import { scriptCollections, collectionScripts, scripts } from '@/lib/db/schema';
|
||||
import { scriptCollections, collectionScripts } from '@/lib/db/schema';
|
||||
import { eq, and, desc } from 'drizzle-orm';
|
||||
import { generateId, ApiError } from './index';
|
||||
|
||||
@ -22,7 +22,7 @@ export async function createCollection(data: CreateCollectionData) {
|
||||
const collectionId = generateId();
|
||||
const now = new Date();
|
||||
|
||||
const [collection] = await db.insert(scriptCollections).values({
|
||||
await db.insert(scriptCollections).values({
|
||||
id: collectionId,
|
||||
name: data.name,
|
||||
description: data.description,
|
||||
@ -30,7 +30,17 @@ export async function createCollection(data: CreateCollectionData) {
|
||||
isPublic: data.isPublic ?? true,
|
||||
createdAt: now,
|
||||
updatedAt: now,
|
||||
}).returning();
|
||||
});
|
||||
|
||||
const collection = {
|
||||
id: collectionId,
|
||||
name: data.name,
|
||||
description: data.description,
|
||||
authorId: data.authorId,
|
||||
isPublic: data.isPublic ?? true,
|
||||
createdAt: now,
|
||||
updatedAt: now,
|
||||
};
|
||||
|
||||
return collection;
|
||||
} catch (error) {
|
||||
@ -150,11 +160,12 @@ export async function updateCollection(id: string, data: UpdateCollectionData, u
|
||||
updatedAt: new Date(),
|
||||
};
|
||||
|
||||
const [updatedCollection] = await db
|
||||
await db
|
||||
.update(scriptCollections)
|
||||
.set(updateData)
|
||||
.where(eq(scriptCollections.id, id))
|
||||
.returning();
|
||||
.where(eq(scriptCollections.id, id));
|
||||
|
||||
const updatedCollection = { ...collection, ...updateData };
|
||||
|
||||
return updatedCollection;
|
||||
} catch (error) {
|
||||
@ -205,14 +216,16 @@ export async function addScriptToCollection(collectionId: string, scriptId: stri
|
||||
throw new ApiError('Script is already in this collection', 400);
|
||||
}
|
||||
|
||||
const [collectionScript] = await db.insert(collectionScripts).values({
|
||||
const collectionScriptData = {
|
||||
id: generateId(),
|
||||
collectionId,
|
||||
scriptId,
|
||||
addedAt: new Date(),
|
||||
}).returning();
|
||||
};
|
||||
|
||||
return collectionScript;
|
||||
await db.insert(collectionScripts).values(collectionScriptData);
|
||||
|
||||
return collectionScriptData;
|
||||
} catch (error) {
|
||||
if (error instanceof ApiError) throw error;
|
||||
throw new ApiError(`Failed to add script to collection: ${error}`, 500);
|
||||
|
@ -1,6 +1,3 @@
|
||||
import { db } from '@/lib/db';
|
||||
import { scripts, users, ratings, scriptVersions, scriptAnalytics, scriptCollections, collectionScripts } from '@/lib/db/schema';
|
||||
import { eq, desc, asc, and, or, like, count, sql } from 'drizzle-orm';
|
||||
import { nanoid } from 'nanoid';
|
||||
|
||||
// Generate unique IDs
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { db } from '@/lib/db';
|
||||
import { ratings, scripts } from '@/lib/db/schema';
|
||||
import { eq, and, avg, count, sql } from 'drizzle-orm';
|
||||
import { eq, and, avg, count } from 'drizzle-orm';
|
||||
import { generateId, ApiError } from './index';
|
||||
|
||||
export interface CreateRatingData {
|
||||
@ -27,24 +27,31 @@ export async function rateScript(data: CreateRatingData) {
|
||||
let ratingRecord;
|
||||
if (existingRating) {
|
||||
// Update existing rating
|
||||
[ratingRecord] = await db
|
||||
await db
|
||||
.update(ratings)
|
||||
.set({
|
||||
rating: data.rating,
|
||||
updatedAt: new Date(),
|
||||
})
|
||||
.where(eq(ratings.id, existingRating.id))
|
||||
.returning();
|
||||
.where(eq(ratings.id, existingRating.id));
|
||||
|
||||
ratingRecord = {
|
||||
...existingRating,
|
||||
rating: data.rating,
|
||||
updatedAt: new Date(),
|
||||
};
|
||||
} else {
|
||||
// Create new rating
|
||||
[ratingRecord] = await db.insert(ratings).values({
|
||||
ratingRecord = {
|
||||
id: generateId(),
|
||||
scriptId: data.scriptId,
|
||||
userId: data.userId,
|
||||
rating: data.rating,
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date(),
|
||||
}).returning();
|
||||
};
|
||||
|
||||
await db.insert(ratings).values(ratingRecord);
|
||||
}
|
||||
|
||||
// Update script's average rating and count
|
||||
@ -107,7 +114,7 @@ async function updateScriptRating(scriptId: string) {
|
||||
.from(ratings)
|
||||
.where(eq(ratings.scriptId, scriptId));
|
||||
|
||||
const avgRating = stats.avgRating ? Math.round(stats.avgRating * 10) / 10 : 0;
|
||||
const avgRating = stats.avgRating ? Math.round(Number(stats.avgRating) * 10) / 10 : 0;
|
||||
const ratingCount = stats.ratingCount || 0;
|
||||
|
||||
await db
|
||||
@ -174,7 +181,7 @@ export async function getScriptRatingStats(scriptId: string) {
|
||||
.where(eq(ratings.scriptId, scriptId));
|
||||
|
||||
return {
|
||||
averageRating: totals.avgRating ? Math.round(totals.avgRating * 10) / 10 : 0,
|
||||
averageRating: totals.avgRating ? Math.round(Number(totals.avgRating) * 10) / 10 : 0,
|
||||
totalRatings: totals.totalRatings || 0,
|
||||
distribution,
|
||||
};
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { db } from '@/lib/db';
|
||||
import { scripts, scriptVersions, users, ratings } from '@/lib/db/schema';
|
||||
import { scripts, scriptVersions, ratings } from '@/lib/db/schema';
|
||||
import { eq, desc, asc, and, or, like, count, sql } from 'drizzle-orm';
|
||||
import { generateId, ApiError } from './index';
|
||||
|
||||
@ -178,27 +178,27 @@ export async function getScripts(filters: ScriptFilters = {}) {
|
||||
}
|
||||
|
||||
if (conditions.length > 0) {
|
||||
query = query.where(and(...conditions));
|
||||
query = query.where(and(...conditions)) as any;
|
||||
}
|
||||
|
||||
// Apply sorting
|
||||
switch (sortBy) {
|
||||
case 'newest':
|
||||
query = query.orderBy(desc(scripts.createdAt));
|
||||
query = query.orderBy(desc(scripts.createdAt)) as any;
|
||||
break;
|
||||
case 'oldest':
|
||||
query = query.orderBy(asc(scripts.createdAt));
|
||||
query = query.orderBy(asc(scripts.createdAt)) as any;
|
||||
break;
|
||||
case 'popular':
|
||||
query = query.orderBy(desc(scripts.viewCount));
|
||||
query = query.orderBy(desc(scripts.viewCount)) as any;
|
||||
break;
|
||||
case 'rating':
|
||||
query = query.orderBy(desc(scripts.rating));
|
||||
query = query.orderBy(desc(scripts.rating)) as any;
|
||||
break;
|
||||
}
|
||||
|
||||
// Apply pagination
|
||||
query = query.limit(limit).offset(offset);
|
||||
query = query.limit(limit).offset(offset) as any;
|
||||
|
||||
const results = await query;
|
||||
|
||||
@ -232,11 +232,12 @@ export async function updateScript(id: string, data: UpdateScriptData, userId: s
|
||||
updatedAt: new Date(),
|
||||
};
|
||||
|
||||
const [updatedScript] = await db
|
||||
await db
|
||||
.update(scripts)
|
||||
.set(updateData)
|
||||
.where(eq(scripts.id, id))
|
||||
.returning();
|
||||
.where(eq(scripts.id, id));
|
||||
|
||||
const updatedScript = { ...script, ...updateData };
|
||||
|
||||
// If content changed, create new version
|
||||
if (data.content && data.version) {
|
||||
@ -279,18 +280,23 @@ export async function deleteScript(id: string, userId: string) {
|
||||
}
|
||||
|
||||
// Approve/reject script (admin only)
|
||||
export async function moderateScript(id: string, isApproved: boolean, moderatorId: string) {
|
||||
export async function moderateScript(id: string, isApproved: boolean, _moderatorId: string) {
|
||||
try {
|
||||
const [updatedScript] = await db
|
||||
const script = await getScriptById(id);
|
||||
if (!script) {
|
||||
throw new ApiError('Script not found', 404);
|
||||
}
|
||||
|
||||
await db
|
||||
.update(scripts)
|
||||
.set({
|
||||
isApproved,
|
||||
updatedAt: new Date(),
|
||||
})
|
||||
.where(eq(scripts.id, id))
|
||||
.returning();
|
||||
.where(eq(scripts.id, id));
|
||||
|
||||
return updatedScript;
|
||||
const moderatedScript = { ...script, isApproved, updatedAt: new Date() };
|
||||
return moderatedScript;
|
||||
} catch (error) {
|
||||
throw new ApiError(`Failed to moderate script: ${error}`, 500);
|
||||
}
|
||||
|
@ -24,20 +24,22 @@ export async function createUser(data: CreateUserData) {
|
||||
const userId = generateId();
|
||||
const now = new Date();
|
||||
|
||||
const [user] = await db.insert(users).values({
|
||||
const userData = {
|
||||
id: userId,
|
||||
email: data.email,
|
||||
username: data.username,
|
||||
displayName: data.displayName,
|
||||
avatarUrl: data.avatarUrl,
|
||||
bio: data.bio,
|
||||
avatarUrl: data.avatarUrl || null,
|
||||
bio: data.bio || null,
|
||||
isAdmin: false,
|
||||
isModerator: false,
|
||||
passwordHash: '', // This should be set by auth layer
|
||||
createdAt: now,
|
||||
updatedAt: now,
|
||||
}).returning();
|
||||
};
|
||||
|
||||
return user;
|
||||
await db.insert(users).values(userData);
|
||||
return userData;
|
||||
} catch (error) {
|
||||
throw new ApiError(`Failed to create user: ${error}`, 500);
|
||||
}
|
||||
@ -95,17 +97,19 @@ export async function getUserByUsername(username: string) {
|
||||
// Update user
|
||||
export async function updateUser(id: string, data: UpdateUserData) {
|
||||
try {
|
||||
const user = await getUserById(id);
|
||||
|
||||
const updateData = {
|
||||
...data,
|
||||
updatedAt: new Date(),
|
||||
};
|
||||
|
||||
const [updatedUser] = await db
|
||||
await db
|
||||
.update(users)
|
||||
.set(updateData)
|
||||
.where(eq(users.id, id))
|
||||
.returning();
|
||||
.where(eq(users.id, id));
|
||||
|
||||
const updatedUser = { ...user, ...updateData };
|
||||
return updatedUser;
|
||||
} catch (error) {
|
||||
throw new ApiError(`Failed to update user: ${error}`, 500);
|
||||
@ -118,17 +122,19 @@ export async function updateUserPermissions(
|
||||
permissions: { isAdmin?: boolean; isModerator?: boolean }
|
||||
) {
|
||||
try {
|
||||
const user = await getUserById(id);
|
||||
|
||||
const updateData = {
|
||||
...permissions,
|
||||
updatedAt: new Date(),
|
||||
};
|
||||
|
||||
const [updatedUser] = await db
|
||||
await db
|
||||
.update(users)
|
||||
.set(updateData)
|
||||
.where(eq(users.id, id))
|
||||
.returning();
|
||||
.where(eq(users.id, id));
|
||||
|
||||
const updatedUser = { ...user, ...updateData };
|
||||
return updatedUser;
|
||||
} catch (error) {
|
||||
throw new ApiError(`Failed to update user permissions: ${error}`, 500);
|
||||
|
33
src/lib/db/browser.ts
Normal file
33
src/lib/db/browser.ts
Normal file
@ -0,0 +1,33 @@
|
||||
// Browser-compatible database interface
|
||||
// This provides mock implementations for browser builds
|
||||
|
||||
export const db = {
|
||||
query: {
|
||||
users: {
|
||||
findFirst: () => Promise.resolve(null),
|
||||
findMany: () => Promise.resolve([]),
|
||||
},
|
||||
scripts: {
|
||||
findFirst: () => Promise.resolve(null),
|
||||
findMany: () => Promise.resolve([]),
|
||||
},
|
||||
},
|
||||
select: () => ({ from: () => ({ where: () => Promise.resolve([]) }) }),
|
||||
insert: () => ({ values: () => Promise.resolve() }),
|
||||
update: () => ({ set: () => ({ where: () => Promise.resolve() }) }),
|
||||
delete: () => ({ where: () => Promise.resolve() }),
|
||||
};
|
||||
|
||||
// Export schema as empty objects for browser compatibility
|
||||
export const users = {};
|
||||
export const scripts = {};
|
||||
export const ratings = {};
|
||||
export const scriptVersions = {};
|
||||
export const scriptAnalytics = {};
|
||||
export const scriptCollections = {};
|
||||
export const collectionScripts = {};
|
||||
|
||||
// Export empty relations
|
||||
export const usersRelations = {};
|
||||
export const scriptsRelations = {};
|
||||
export const ratingsRelations = {};
|
Reference in New Issue
Block a user