feat: profile page + 404 page + refactor code
This commit is contained in:
parent
3f137e5c3c
commit
d692e86fe0
17 changed files with 1282 additions and 313 deletions
|
|
@ -35,8 +35,6 @@ export async function GET({ params, request }) {
|
|||
userName: user.name,
|
||||
userUsername: user.username,
|
||||
userImage: user.image,
|
||||
userBio: user.bio,
|
||||
userCreatedAt: user.createdAt,
|
||||
isLikedByUser: session?.user ?
|
||||
sql<boolean>`EXISTS(SELECT 1 FROM ${commentLike} WHERE ${commentLike.userId} = ${session.user.id} AND ${commentLike.commentId} = ${comment.id})` :
|
||||
sql<boolean>`FALSE`
|
||||
|
|
@ -109,8 +107,6 @@ export async function POST({ request, params }) {
|
|||
userName: user.name,
|
||||
userUsername: user.username,
|
||||
userImage: user.image,
|
||||
userBio: user.bio,
|
||||
userCreatedAt: user.createdAt,
|
||||
isLikedByUser: sql<boolean>`FALSE`
|
||||
})
|
||||
.from(comment)
|
||||
|
|
|
|||
139
website/src/routes/api/user/[userId]/+server.ts
Normal file
139
website/src/routes/api/user/[userId]/+server.ts
Normal file
|
|
@ -0,0 +1,139 @@
|
|||
import { json, error } from '@sveltejs/kit';
|
||||
import { db } from '$lib/server/db';
|
||||
import { user, coin, transaction, userPortfolio } from '$lib/server/db/schema';
|
||||
import { eq, desc, sql, count, and, gte } from 'drizzle-orm';
|
||||
|
||||
export async function GET({ params }) {
|
||||
const { userId } = params;
|
||||
|
||||
if (!userId) {
|
||||
throw error(400, 'User ID or username is required');
|
||||
}
|
||||
|
||||
try {
|
||||
const isNumeric = /^\d+$/.test(userId);
|
||||
|
||||
const userProfile = await db.query.user.findFirst({
|
||||
where: isNumeric ? eq(user.id, parseInt(userId)) : eq(user.username, userId),
|
||||
columns: {
|
||||
id: true,
|
||||
name: true,
|
||||
username: true,
|
||||
bio: true,
|
||||
image: true,
|
||||
createdAt: true,
|
||||
baseCurrencyBalance: true,
|
||||
isAdmin: true,
|
||||
}
|
||||
});
|
||||
|
||||
if (!userProfile) {
|
||||
throw error(404, 'User not found');
|
||||
}
|
||||
|
||||
const actualUserId = userProfile.id;
|
||||
|
||||
// get created coins
|
||||
const createdCoins = await db
|
||||
.select({
|
||||
id: coin.id,
|
||||
name: coin.name,
|
||||
symbol: coin.symbol,
|
||||
icon: coin.icon,
|
||||
currentPrice: coin.currentPrice,
|
||||
marketCap: coin.marketCap,
|
||||
volume24h: coin.volume24h,
|
||||
change24h: coin.change24h,
|
||||
createdAt: coin.createdAt,
|
||||
})
|
||||
.from(coin)
|
||||
.where(eq(coin.creatorId, actualUserId))
|
||||
.orderBy(desc(coin.createdAt))
|
||||
.limit(10);
|
||||
|
||||
// get portfolio value and holdings count
|
||||
const portfolioStats = await db
|
||||
.select({
|
||||
holdingsCount: count(),
|
||||
totalValue: sql<number>`COALESCE(SUM(CAST(${userPortfolio.quantity} AS NUMERIC) * CAST(${coin.currentPrice} AS NUMERIC)), 0)`
|
||||
})
|
||||
.from(userPortfolio)
|
||||
.innerJoin(coin, eq(userPortfolio.coinId, coin.id))
|
||||
.where(eq(userPortfolio.userId, actualUserId));
|
||||
|
||||
// get recent transactions
|
||||
const recentTransactions = await db
|
||||
.select({
|
||||
id: transaction.id,
|
||||
type: transaction.type,
|
||||
coinSymbol: coin.symbol,
|
||||
coinName: coin.name,
|
||||
coinIcon: coin.icon,
|
||||
quantity: transaction.quantity,
|
||||
pricePerCoin: transaction.pricePerCoin,
|
||||
totalBaseCurrencyAmount: transaction.totalBaseCurrencyAmount,
|
||||
timestamp: transaction.timestamp,
|
||||
})
|
||||
.from(transaction)
|
||||
.innerJoin(coin, eq(transaction.coinId, coin.id))
|
||||
.where(eq(transaction.userId, actualUserId))
|
||||
.orderBy(desc(transaction.timestamp))
|
||||
.limit(10);
|
||||
|
||||
// calc total portfolio value
|
||||
const baseCurrencyBalance = parseFloat(userProfile.baseCurrencyBalance);
|
||||
const holdingsValue = portfolioStats[0]?.totalValue || 0;
|
||||
const totalPortfolioValue = baseCurrencyBalance + holdingsValue;
|
||||
|
||||
// get all transaction statistics
|
||||
const transactionStats = await db
|
||||
.select({
|
||||
totalTransactions: count(),
|
||||
totalBuyVolume: sql<number>`COALESCE(SUM(CASE WHEN ${transaction.type} = 'BUY' THEN CAST(${transaction.totalBaseCurrencyAmount} AS NUMERIC) ELSE 0 END), 0)`,
|
||||
totalSellVolume: sql<number>`COALESCE(SUM(CASE WHEN ${transaction.type} = 'SELL' THEN CAST(${transaction.totalBaseCurrencyAmount} AS NUMERIC) ELSE 0 END), 0)`
|
||||
})
|
||||
.from(transaction)
|
||||
.where(eq(transaction.userId, actualUserId));
|
||||
|
||||
const twentyFourHoursAgo = new Date(Date.now() - 24 * 60 * 60 * 1000);
|
||||
const transactionStats24h = await db
|
||||
.select({
|
||||
transactions24h: count(),
|
||||
buyVolume24h: sql<number>`COALESCE(SUM(CASE WHEN ${transaction.type} = 'BUY' THEN CAST(${transaction.totalBaseCurrencyAmount} AS NUMERIC) ELSE 0 END), 0)`,
|
||||
sellVolume24h: sql<number>`COALESCE(SUM(CASE WHEN ${transaction.type} = 'SELL' THEN CAST(${transaction.totalBaseCurrencyAmount} AS NUMERIC) ELSE 0 END), 0)`
|
||||
})
|
||||
.from(transaction)
|
||||
.where(
|
||||
and(
|
||||
eq(transaction.userId, actualUserId),
|
||||
gte(transaction.timestamp, twentyFourHoursAgo)
|
||||
)
|
||||
);
|
||||
|
||||
return json({
|
||||
profile: {
|
||||
...userProfile,
|
||||
baseCurrencyBalance,
|
||||
totalPortfolioValue,
|
||||
},
|
||||
stats: {
|
||||
totalPortfolioValue,
|
||||
baseCurrencyBalance,
|
||||
holdingsValue,
|
||||
holdingsCount: portfolioStats[0]?.holdingsCount || 0,
|
||||
coinsCreated: createdCoins.length,
|
||||
totalTransactions: transactionStats[0]?.totalTransactions || 0,
|
||||
totalBuyVolume: transactionStats[0]?.totalBuyVolume || 0,
|
||||
totalSellVolume: transactionStats[0]?.totalSellVolume || 0,
|
||||
transactions24h: transactionStats24h[0]?.transactions24h || 0,
|
||||
buyVolume24h: transactionStats24h[0]?.buyVolume24h || 0,
|
||||
sellVolume24h: transactionStats24h[0]?.sellVolume24h || 0,
|
||||
},
|
||||
createdCoins,
|
||||
recentTransactions
|
||||
});
|
||||
} catch (e) {
|
||||
console.error('Failed to fetch user profile:', e);
|
||||
throw error(500, 'Failed to fetch user profile');
|
||||
}
|
||||
}
|
||||
Reference in a new issue