first day of vibe coding

This commit is contained in:
k
2026-04-20 22:11:18 +08:00
commit 1747fc489f
38 changed files with 15267 additions and 0 deletions
+50
View File
@@ -0,0 +1,50 @@
import type { TrumpPost, Candle, BotTrade, BotPerformance } from '@/types'
const BASE_URL = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:8000'
async function fetchJson<T>(path: string, init?: RequestInit): Promise<T> {
const res = await fetch(`${BASE_URL}/api${path}`, {
headers: { 'Content-Type': 'application/json' },
...init,
})
if (!res.ok) throw new Error(`API error ${res.status}: ${path}`)
return res.json() as Promise<T>
}
export async function getPosts(limit = 20, page = 1): Promise<TrumpPost[]> {
return fetchJson<TrumpPost[]>(`/posts?limit=${limit}&page=${page}`)
}
export async function getPost(id: number): Promise<TrumpPost> {
return fetchJson<TrumpPost>(`/posts/${id}`)
}
export async function getPrices(asset: 'BTC' | 'ETH', tf: string): Promise<Candle[]> {
return fetchJson<Candle[]>(`/prices/${asset}?tf=${tf}`)
}
export async function getTrades(limit = 20, page = 1): Promise<BotTrade[]> {
return fetchJson<BotTrade[]>(`/trades?limit=${limit}&page=${page}`)
}
export async function getPerformance(): Promise<BotPerformance> {
return fetchJson<BotPerformance>(`/performance`)
}
export async function subscribe(
wallet: string,
signature: string,
): Promise<{ success: boolean; message: string }> {
return fetchJson<{ success: boolean; message: string }>(`/subscribe`, {
method: 'POST',
body: JSON.stringify({ wallet, signature }),
})
}
export async function getUser(
wallet: string,
): Promise<{ wallet_address: string; active: boolean; subscribed_at: string | null; hl_api_key_set: boolean; trades: BotTrade[] }> {
return fetchJson<{ wallet_address: string; active: boolean; subscribed_at: string | null; hl_api_key_set: boolean; trades: BotTrade[] }>(
`/user/${wallet}`,
)
}
+53
View File
@@ -0,0 +1,53 @@
'use client'
import { useEffect, useRef, useCallback } from 'react'
const WS_URL = process.env.NEXT_PUBLIC_WS_URL || 'ws://localhost:8000'
type PriceUpdate = { type: 'price'; asset: 'BTC' | 'ETH'; price: number }
type PostUpdate = { type: 'new_post'; post: object }
type WsMessage = PriceUpdate | PostUpdate
interface Handlers {
onPrice?: (asset: 'BTC' | 'ETH', price: number) => void
onNewPost?: (post: object) => void
}
export function usePriceSocket(handlers: Handlers) {
const wsRef = useRef<WebSocket | null>(null)
const handlersRef = useRef(handlers)
handlersRef.current = handlers
const connect = useCallback(() => {
const ws = new WebSocket(`${WS_URL}/ws/prices`)
wsRef.current = ws
ws.onmessage = (e) => {
try {
const msg: WsMessage = JSON.parse(e.data)
if (msg.type === 'price' && handlersRef.current.onPrice) {
handlersRef.current.onPrice(msg.asset, msg.price)
} else if (msg.type === 'new_post' && handlersRef.current.onNewPost) {
handlersRef.current.onNewPost(msg.post)
}
} catch {
// ignore malformed messages
}
}
ws.onclose = () => {
setTimeout(connect, 3000)
}
ws.onerror = () => {
ws.close()
}
}, [])
useEffect(() => {
connect()
return () => {
wsRef.current?.close()
}
}, [connect])
}
+33
View File
@@ -0,0 +1,33 @@
export function formatPrice(n: number): string {
return '$' + n.toLocaleString('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 2 })
}
export function formatPct(n: number): string {
const sign = n >= 0 ? '+' : ''
return `${sign}${n.toFixed(2)}%`
}
export function formatHold(seconds: number): string {
if (seconds < 60) return `${seconds}s`
const h = Math.floor(seconds / 3600)
const m = Math.floor((seconds % 3600) / 60)
if (h === 0) return `${m}m`
if (m === 0) return `${h}h`
return `${h}h ${m}m`
}
export function shortenAddress(addr: string): string {
if (addr.length < 10) return addr
return `${addr.slice(0, 6)}...${addr.slice(-4)}`
}
export function sentimentColor(s: string): string {
switch (s) {
case 'bullish':
return '#4ade80'
case 'bearish':
return '#ef4444'
default:
return '#555555'
}
}
+13
View File
@@ -0,0 +1,13 @@
import { createConfig, http } from 'wagmi'
import { mainnet } from 'wagmi/chains'
import { metaMask } from 'wagmi/connectors'
export const chains = [mainnet] as const
export const config = createConfig({
chains,
connectors: [metaMask()],
transports: {
[mainnet.id]: http(),
},
})