feat: live trades (/live & sidebar) + sidebar skeleton
This commit is contained in:
parent
37d76b243b
commit
0ddb431536
12 changed files with 785 additions and 175 deletions
|
|
@ -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',
|
||||
|
|
|
|||
57
website/src/routes/api/trades/recent/+server.ts
Normal file
57
website/src/routes/api/trades/recent/+server.ts
Normal 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: [] });
|
||||
}
|
||||
}
|
||||
Reference in a new issue