feat: live trades (/live & sidebar) + sidebar skeleton

This commit is contained in:
Face 2025-05-26 15:06:45 +03:00
parent 37d76b243b
commit 0ddb431536
12 changed files with 785 additions and 175 deletions

View file

@ -3,6 +3,7 @@ import { error, json } from '@sveltejs/kit';
import { db } from '$lib/server/db';
import { coin, userPortfolio, user, transaction, priceHistory } from '$lib/server/db/schema';
import { eq, and, gte } from 'drizzle-orm';
import { redis } from '$lib/server/redis';
async function calculate24hMetrics(coinId: number, currentPrice: number) {
const twentyFourHoursAgo = new Date(Date.now() - 24 * 60 * 60 * 1000);
@ -74,7 +75,11 @@ export async function POST({ params, request }) {
throw error(400, 'This coin is delisted and cannot be traded');
}
const [userData] = await db.select({ baseCurrencyBalance: user.baseCurrencyBalance }).from(user).where(eq(user.id, userId)).limit(1);
const [userData] = await db.select({
baseCurrencyBalance: user.baseCurrencyBalance,
username: user.username,
image: user.image
}).from(user).where(eq(user.id, userId)).limit(1);
if (!userData) {
throw error(404, 'User not found');
@ -177,6 +182,34 @@ export async function POST({ params, request }) {
.where(eq(coin.id, coinData.id));
});
// REDIS
const tradeData = {
type: 'BUY',
username: userData.username,
userImage: userData.image || '',
amount: coinsBought,
coinSymbol: normalizedSymbol,
coinName: coinData.name,
coinIcon: coinData.icon || '',
totalValue: totalCost,
price: newPrice,
timestamp: Date.now(),
userId: userId.toString()
};
await redis.publish('trades:all', JSON.stringify({
type: 'all-trades',
data: tradeData
}));
if (totalCost >= 1000) {
await redis.publish('trades:large', JSON.stringify({
type: 'live-trade',
data: tradeData
}));
}
// End REDIS
return json({
success: true,
type: 'BUY',
@ -282,6 +315,34 @@ export async function POST({ params, request }) {
.where(eq(coin.id, coinData.id));
});
// REDIS
const tradeData = {
type: 'SELL',
username: userData.username,
userImage: userData.image || '',
amount: amount,
coinSymbol: normalizedSymbol,
coinName: coinData.name,
coinIcon: coinData.icon || '',
totalValue: totalCost,
price: newPrice,
timestamp: Date.now(),
userId: userId.toString()
};
await redis.publish('trades:all', JSON.stringify({
type: 'all-trades',
data: tradeData
}));
if (totalCost >= 1000) {
await redis.publish('trades:large', JSON.stringify({
type: 'live-trade',
data: tradeData
}));
}
// End REDIS
return json({
success: true,
type: 'SELL',

View file

@ -0,0 +1,57 @@
import { json } from '@sveltejs/kit';
import { db } from '$lib/server/db';
import { transaction, user, coin } from '$lib/server/db/schema';
import { desc, gte, eq } from 'drizzle-orm';
import { validateSearchParams } from '$lib/utils/validation';
export async function GET({ url }) {
const params = validateSearchParams(url.searchParams);
const limit = params.getPositiveInt('limit', 100);
const minValue = params.getNonNegativeFloat('minValue', 0);
try {
const trades = await db
.select({
type: transaction.type,
username: user.username,
userImage: user.image,
amount: transaction.quantity,
coinSymbol: coin.symbol,
coinName: coin.name,
coinIcon: coin.icon,
totalValue: transaction.totalBaseCurrencyAmount,
price: transaction.pricePerCoin,
timestamp: transaction.timestamp,
userId: transaction.userId
})
.from(transaction)
.innerJoin(user, eq(user.id, transaction.userId))
.innerJoin(coin, eq(coin.id, transaction.coinId))
.where(
minValue > 0
? gte(transaction.totalBaseCurrencyAmount, minValue.toString())
: undefined
)
.orderBy(desc(transaction.timestamp))
.limit(limit);
const formattedTrades = trades.map(trade => ({
type: trade.type as 'BUY' | 'SELL',
username: trade.username,
userImage: trade.userImage,
amount: Number(trade.amount),
coinSymbol: trade.coinSymbol,
coinName: trade.coinName,
coinIcon: trade.coinIcon,
totalValue: Number(trade.totalValue),
price: Number(trade.price),
timestamp: trade.timestamp.getTime(),
userId: trade.userId.toString()
}));
return json({ trades: formattedTrades });
} catch (error) {
console.error('Error fetching recent trades:', error);
return json({ trades: [] });
}
}