Consolidate all crypto content to /crypto-project; clean homepage and global layout#119
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
…homepage and global layout Agent-Logs-Url: https://github.com/DarkModder33/main/sessions/6888a4c4-f6d7-4175-a21d-03a943941ea9 Co-authored-by: DarkModder33 <254196519+DarkModder33@users.noreply.github.com>
🔗 Link AuditStatus: ❌ Failed Top findings
|
Reviewer's GuideConsolidates all crypto/trading/Web3 functionality and content into a rebuilt /crypto-project landing page, removes crypto exposure from the homepage and non-crypto surfaces, converts legacy crypto/trading routes to redirects, and deletes the now-unused frontend and backend trading stack. Sequence diagram for MarketTicker conditional rendering on /crypto-projectsequenceDiagram
participant User
participant Browser
participant Nextjs_app
participant MarketTicker
participant ExternalScript as TradingView_script
User->>Browser: Navigate_to_route
Browser->>Nextjs_app: Request_page
Nextjs_app-->>Browser: HTML_with_MarketTicker_component
Browser->>MarketTicker: Mount_component
MarketTicker->>MarketTicker: pathname = usePathname()
alt pathname_is_crypto-project
MarketTicker->>MarketTicker: showTicker = true
MarketTicker->>ExternalScript: Inject_and_load_ticker_script
ExternalScript-->>MarketTicker: Initialize_BTC_ETH_SOL_AVAX_tape
else pathname_is_not_crypto-project
MarketTicker->>MarketTicker: showTicker = false
MarketTicker-->>Browser: Render_null
end
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
There was a problem hiding this comment.
Hey - I've found 1 issue, and left some high level feedback:
- In
app/crypto-project/page.tsxyou’re building Tailwind class names dynamically (e.g.bg-${color}-500/10,text-${color}-400), which Tailwind’s JIT/purge won’t see; consider mappingcolorto explicit class strings instead so the styles don’t get stripped in production. app/polymarket/PolymarketClientPage.tsxis now only doing a client-side redirect and is no longer needed as an intermediate dynamic-loader; you can delete this file and haveapp/polymarket/page.tsxhandle the redirect directly to simplify the routing tree.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- In `app/crypto-project/page.tsx` you’re building Tailwind class names dynamically (e.g. `bg-${color}-500/10`, `text-${color}-400`), which Tailwind’s JIT/purge won’t see; consider mapping `color` to explicit class strings instead so the styles don’t get stripped in production.
- `app/polymarket/PolymarketClientPage.tsx` is now only doing a client-side redirect and is no longer needed as an intermediate dynamic-loader; you can delete this file and have `app/polymarket/page.tsx` handle the redirect directly to simplify the routing tree.
## Individual Comments
### Comment 1
<location path="app/crypto-project/page.tsx" line_range="189-191" />
<code_context>
+ </p>
+ </div>
+ <div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-3">
+ {capabilities.map(({ icon: Icon, title, description, color }) => (
+ <article key={title} className="theme-grid-card">
+ <div className={`w-10 h-10 flex items-center justify-center rounded-xl bg-${color}-500/10 mb-4`}>
+ <Icon className={`w-5 h-5 text-${color}-400`} />
+ </div>
</code_context>
<issue_to_address>
**suggestion (bug_risk):** Dynamic Tailwind color classes may be purged unless explicitly safelisted.
These interpolations (`bg-${color}-500/10`, `text-${color}-400`, and similar) won’t be detected by Tailwind’s class scanner because the full class names don’t appear in the source. To avoid them being purged, either map colors to static class strings (e.g. `const COLOR_CLASSES = { cyan: 'bg-cyan-500/10 text-cyan-400', ... }`) or add a safelist pattern in `tailwind.config.js` that covers all variants you use.
Suggested implementation:
```typescript
<div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-3">
{capabilities.map(({ icon: Icon, title, description, color }) => (
<article key={title} className="theme-grid-card">
<div
className={`w-10 h-10 flex items-center justify-center rounded-xl ${
({
cyan: 'bg-cyan-500/10',
emerald: 'bg-emerald-500/10',
violet: 'bg-violet-500/10',
sky: 'bg-sky-500/10',
amber: 'bg-amber-500/10',
rose: 'bg-rose-500/10',
} as Record<string, string>)[color] ?? 'bg-zinc-500/10'
} mb-4`}
>
<Icon
className={`w-5 h-5 ${
({
cyan: 'text-cyan-400',
emerald: 'text-emerald-400',
violet: 'text-violet-400',
sky: 'text-sky-400',
amber: 'text-amber-400',
rose: 'text-rose-400',
} as Record<string, string>)[color] ?? 'text-zinc-400'
}`}
/>
</div>
```
1. Confirm the actual set of `color` values used in `capabilities` and expand/adjust the inline maps accordingly so each color has a corresponding static Tailwind class.
2. If you prefer to avoid repeating the color map in JSX, you can extract those maps to top-level `const` objects (e.g. `const CAPABILITY_BG_CLASSES = { ... }`) and reference them in the same way; the important part is that all Tailwind classes remain as static string literals.
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
| {capabilities.map(({ icon: Icon, title, description, color }) => ( | ||
| <article key={title} className="theme-grid-card"> | ||
| <div className={`w-10 h-10 flex items-center justify-center rounded-xl bg-${color}-500/10 mb-4`}> |
There was a problem hiding this comment.
suggestion (bug_risk): Dynamic Tailwind color classes may be purged unless explicitly safelisted.
These interpolations (bg-${color}-500/10, text-${color}-400, and similar) won’t be detected by Tailwind’s class scanner because the full class names don’t appear in the source. To avoid them being purged, either map colors to static class strings (e.g. const COLOR_CLASSES = { cyan: 'bg-cyan-500/10 text-cyan-400', ... }) or add a safelist pattern in tailwind.config.js that covers all variants you use.
Suggested implementation:
<div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-3">
{capabilities.map(({ icon: Icon, title, description, color }) => (
<article key={title} className="theme-grid-card">
<div
className={`w-10 h-10 flex items-center justify-center rounded-xl ${
({
cyan: 'bg-cyan-500/10',
emerald: 'bg-emerald-500/10',
violet: 'bg-violet-500/10',
sky: 'bg-sky-500/10',
amber: 'bg-amber-500/10',
rose: 'bg-rose-500/10',
} as Record<string, string>)[color] ?? 'bg-zinc-500/10'
} mb-4`}
>
<Icon
className={`w-5 h-5 ${
({
cyan: 'text-cyan-400',
emerald: 'text-emerald-400',
violet: 'text-violet-400',
sky: 'text-sky-400',
amber: 'text-amber-400',
rose: 'text-rose-400',
} as Record<string, string>)[color] ?? 'text-zinc-400'
}`}
/>
</div>- Confirm the actual set of
colorvalues used incapabilitiesand expand/adjust the inline maps accordingly so each color has a corresponding static Tailwind class. - If you prefer to avoid repeating the color map in JSX, you can extract those maps to top-level
constobjects (e.g.const CAPABILITY_BG_CLASSES = { ... }) and reference them in the same way; the important part is that all Tailwind classes remain as static string literals.
There was a problem hiding this comment.
Pull request overview
This PR consolidates all crypto/trading/Web3 user-facing content into the /crypto-project product page, removes crypto surfaces from the homepage/global UI, and deletes the now-dead trading feature implementation (UI, hooks, libs, and API routes).
Changes:
- Restricts
MarketTickerto render only on/crypto-projectand replaces the crypto-themedLiveActivityentry with a neutral system message. - Converts legacy crypto/trading routes into redirects to
/crypto-projectand removes crypto-specific links/copy from other hubs (e.g., Intelligence, AI Hub, onboarding). - Deletes trading-related type definitions, UI components, hooks, libraries, and API routes that are no longer referenced.
Reviewed changes
Copilot reviewed 73 out of 73 changed files in this pull request and generated 12 comments.
Show a summary per file
| File | Description |
|---|---|
types/trading.ts |
Deleted shared trading type definitions (no remaining references found). |
lib/trading/tradehax-bot.ts |
Deleted trading bot core implementation. |
lib/trading/strategy-validator.ts |
Deleted strategy validation utility. |
lib/trading/strategy-serializer.ts |
Deleted strategy (de)serialization utilities. |
lib/trading/strategy-builder-types.ts |
Deleted strategy builder type re-exports. |
lib/trading/signal-outlook.ts |
Deleted predictive outlook generator. |
lib/trading/signal-cadence.ts |
Deleted cadence window resolver. |
lib/trading/sentiment-types.ts |
Deleted sentiment type re-exports. |
lib/trading/sentiment-engine.ts |
Deleted sentiment engine implementation. |
lib/trading/portfolio-types.ts |
Deleted portfolio type re-exports. |
lib/trading/portfolio-aggregator.ts |
Deleted portfolio aggregation logic. |
lib/trading/historical-data.ts |
Deleted simulated OHLCV generator utilities. |
lib/trading/explainability-types.ts |
Deleted XAI type re-exports. |
lib/trading/explainability-engine.ts |
Deleted XAI explanation generator. |
lib/trading/exchange-adapters.ts |
Deleted exchange adapter registry + simulated adapters. |
lib/trading/daily-watchlist.ts |
Deleted daily watchlist builder used by deleted cadence cron. |
lib/trading/chain-adapter.ts |
Deleted chain adapter registry + paper adapter. |
lib/trading/backtest-types.ts |
Deleted backtest type re-exports. |
lib/trading/backtest-engine.ts |
Deleted backtest engine implementation. |
hooks/use-sentiment-stream.ts |
Deleted sentiment polling hook. |
hooks/use-portfolio.ts |
Deleted portfolio polling hook. |
components/ui/MarketTicker.tsx |
Shows ticker only on /crypto-project route (previously site-wide). |
components/ui/LiveActivity.tsx |
Replaces market-sentiment activity line with a neutral system message. |
components/trading/strategy-builder/StrategyToolbar.tsx |
Deleted strategy builder toolbar UI. |
components/trading/strategy-builder/StrategyPreview.tsx |
Deleted strategy preview UI. |
components/trading/strategy-builder/StrategyCanvas.tsx |
Deleted strategy canvas UI. |
components/trading/strategy-builder/StrategyBlock.tsx |
Deleted strategy block UI. |
components/trading/SignalTimeline.tsx |
Deleted timeline UI for similar signals. |
components/trading/SignalExplainer.tsx |
Deleted XAI explainer UI. |
components/trading/SentimentGauge.tsx |
Deleted sentiment gauge UI. |
components/trading/SentimentFeed.tsx |
Deleted sentiment feed UI. |
components/trading/RebalanceSuggestions.tsx |
Deleted rebalance suggestions UI. |
components/trading/PortfolioOverview.tsx |
Deleted portfolio dashboard UI. |
components/trading/FactorBreakdown.tsx |
Deleted factor breakdown UI. |
components/trading/ExchangeConnector.tsx |
Deleted exchange connector UI. |
components/trading/ConfidenceMeter.tsx |
Deleted confidence meter UI. |
components/trading/backtest/TradeLog.tsx |
Deleted backtest trade log UI. |
components/trading/backtest/EquityCurve.tsx |
Deleted backtest equity curve UI. |
components/trading/backtest/BacktestStats.tsx |
Deleted backtest stats UI. |
components/trading/backtest/BacktestResults.tsx |
Deleted backtest results UI. |
components/trading/backtest/BacktestForm.tsx |
Deleted backtest form UI. |
components/trading/AssetAllocationChart.tsx |
Deleted allocation chart UI. |
components/intelligence/CryptoFlowPanel.tsx |
Deleted crypto flow panel UI. |
app/crypto-project/page.tsx |
Hosts consolidated crypto project landing page content. |
app/web3-token-roadmap-consulting/page.tsx |
Redirects legacy route to /crypto-project. |
app/trading/xai/page.tsx |
Redirects legacy route to /crypto-project. |
app/trading/strategy-builder/page.tsx |
Redirects legacy route to /crypto-project. |
app/trading/sentiment/page.tsx |
Redirects legacy route to /crypto-project. |
app/trading/portfolio/page.tsx |
Redirects legacy route to /crypto-project. |
app/trading/page.tsx |
Redirects legacy route to /crypto-project. |
app/trading/backtest/page.tsx |
Redirects legacy route to /crypto-project. |
app/intelligence/page.tsx |
Removes crypto-specific copy/links/metrics from the Intelligence hub page. |
app/intelligence/crypto-flow/page.tsx |
Redirects legacy route to /crypto-project. |
app/beginner-ai-crypto-trading-assistant/page.tsx |
Redirects legacy route to /crypto-project. |
app/polymarket/PolymarketClientPage.tsx |
Client-side redirect helper (now effectively unused after server redirect). |
app/polymarket/page.tsx |
Redirects legacy route to /crypto-project. |
app/onboarding/page.tsx |
Updates onboarding link to point to /crypto-project and removes trading-specific phrasing. |
app/ai-hub/page.tsx |
Removes crypto/Web3-specific metadata/FAQ content and adjusts copy toward general market/services usage. |
app/sitemap.ts |
Removes legacy crypto/trading URLs and adds /crypto-project. |
app/api/trading/signal/process/route.ts |
Deleted trading signal processing API route. |
app/api/trading/signal/predictive/route.ts |
Deleted predictive signal feed API route. |
app/api/trading/signal/discord/route.ts |
Deleted Discord dispatch API route for trading signals. |
app/api/trading/bot/create/route.ts |
Deleted trading bot creation API route. |
app/api/trading/bot/[id]/stats/route.ts |
Deleted bot stats API route. |
app/api/signals/explain/route.ts |
Deleted signal explainability API route. |
app/api/sentiment/route.ts |
Deleted sentiment snapshot API route. |
app/api/portfolio/aggregate/route.ts |
Deleted portfolio aggregation API route. |
app/api/intelligence/crypto-flow/route.ts |
Deleted crypto flow intelligence API route. |
app/api/cron/trading/signal-cadence/route.ts |
Deleted cadence cron API route. |
app/api/backtest/run/route.ts |
Deleted backtest execution API route. |
| {capabilities.map(({ icon: Icon, title, description, color }) => ( | ||
| <article key={title} className="theme-grid-card"> | ||
| <div className={`w-10 h-10 flex items-center justify-center rounded-xl bg-${color}-500/10 mb-4`}> | ||
| <Icon className={`w-5 h-5 text-${color}-400`} /> | ||
| </div> | ||
| <h3 className="text-base font-bold text-white mb-2">{title}</h3> | ||
| <p className="text-sm text-zinc-400 leading-relaxed">{description}</p> | ||
| </article> | ||
| ))} |
| import { redirect } from "next/navigation"; | ||
|
|
||
| export const metadata = createPageMetadata({ | ||
| title: "Digital Product Roadmap Consulting | TradeHax AI", | ||
| description: | ||
| "Plan product utility phases, growth milestones, and measurable rollout KPIs with a practical consulting roadmap for your digital business.", | ||
| path: "/web3-token-roadmap-consulting", | ||
| keywords: [ | ||
| "digital product roadmap consulting", | ||
| "product strategy consulting", | ||
| "app development roadmap", | ||
| "digital business strategy", | ||
| ], | ||
| }); | ||
|
|
||
| const serviceJsonLd = { | ||
| "@context": "https://schema.org", | ||
| "@type": "Service", | ||
| name: "Digital Product Roadmap Consulting", | ||
| provider: { | ||
| "@type": "Organization", | ||
| name: "TradeHax AI", | ||
| }, | ||
| serviceType: "Product Strategy Consulting", | ||
| areaServed: "United States", | ||
| description: | ||
| "Product utility planning, phased rollout strategy, growth readiness, and KPI mapping for sustainable digital business growth.", | ||
| }; | ||
|
|
||
| export default function ProductRoadmapConsultingPage() { | ||
| return ( | ||
| <div className="min-h-screen bg-gradient-to-b from-gray-950 via-gray-900 to-black"> | ||
| <Script id="service-product-roadmap" type="application/ld+json" strategy="afterInteractive"> | ||
| {JSON.stringify(serviceJsonLd)} | ||
| </Script> | ||
|
|
||
|
|
||
| <main className="mx-auto w-full max-w-5xl px-4 py-10 sm:px-6 lg:px-8"> | ||
| <section className="rounded-2xl border border-fuchsia-400/20 bg-fuchsia-500/5 p-6 sm:p-8"> | ||
| <p className="text-xs font-semibold uppercase tracking-wider text-fuchsia-200">Product Advisory</p> | ||
| <h1 className="mt-2 text-3xl font-bold text-white sm:text-4xl">Digital Product Roadmap Consulting</h1> | ||
| <p className="mt-3 max-w-3xl text-sm text-zinc-300 sm:text-base"> | ||
| Build a forward-leaning roadmap with practical phases: onboarding, feature utility, retention loops, and growth milestones. | ||
| We focus on measurable outcomes and real business value. | ||
| </p> | ||
|
|
||
| <div className="mt-6 grid gap-3 sm:grid-cols-3"> | ||
| {[ | ||
| "Phase 1: onboarding + user experience", | ||
| "Phase 2: feature loops + engagement", | ||
| "Phase 3: growth + accountability", | ||
| ].map((item) => ( | ||
| <div key={item} className="rounded-xl border border-white/10 bg-black/20 p-3 text-sm text-zinc-200"> | ||
| {item} | ||
| </div> | ||
| ))} | ||
| </div> | ||
|
|
||
| <div className="mt-6 flex flex-wrap gap-2"> | ||
| <TrackedCtaLink | ||
| href="/schedule" | ||
| conversionId="book_ai_consult" | ||
| surface="seo:product_roadmap" | ||
| conversionContext={{ placement: "hero", variant: "book_consult", audience: "all" }} | ||
| className="rounded-full border border-fuchsia-300/40 bg-fuchsia-500/20 px-4 py-2 text-xs font-semibold text-fuchsia-100 hover:bg-fuchsia-500/30" | ||
| > | ||
| Book a Consultation | ||
| </TrackedCtaLink> | ||
| <TrackedCtaLink | ||
| href="/services" | ||
| conversionId="open_services" | ||
| surface="seo:product_roadmap" | ||
| conversionContext={{ placement: "hero", variant: "view_services", audience: "all" }} | ||
| className="rounded-full border border-white/20 bg-white/10 px-4 py-2 text-xs font-semibold text-zinc-100 hover:bg-white/15" | ||
| > | ||
| View All Services | ||
| </TrackedCtaLink> | ||
| </div> | ||
| </section> | ||
| </main> | ||
| </div> | ||
| ); | ||
| export default function WebTokenRoadmapPage() { | ||
| redirect("/crypto-project"); | ||
| } |
| import { redirect } from "next/navigation"; | ||
|
|
||
| export default function BeginnerAiCryptoTradingAssistantPage() { | ||
| return ( | ||
| <div className="min-h-screen bg-gradient-to-b from-gray-950 via-gray-900 to-black"> | ||
| <Script id="faq-beginner-ai-crypto" type="application/ld+json" strategy="afterInteractive"> | ||
| {JSON.stringify(faqJsonLd)} | ||
| </Script> | ||
|
|
||
|
|
||
| <main className="mx-auto w-full max-w-5xl px-4 py-10 sm:px-6 lg:px-8"> | ||
| <section className="rounded-2xl border border-emerald-400/20 bg-emerald-500/5 p-6 sm:p-8"> | ||
| <p className="text-xs font-semibold uppercase tracking-wider text-emerald-200">Beginner Track</p> | ||
| <h1 className="mt-2 text-3xl font-bold text-white sm:text-4xl">Beginner AI Crypto Trading Assistant</h1> | ||
| <p className="mt-3 max-w-3xl text-sm text-zinc-300 sm:text-base"> | ||
| Get operator-grade guidance without overwhelm. Build confidence with risk-aware playbooks, structured prompts, | ||
| and clear execution checkpoints. | ||
| </p> | ||
|
|
||
| <div className="mt-6 grid gap-3 sm:grid-cols-3"> | ||
| {[ | ||
| "Define thesis + invalidation before entry", | ||
| "Use bounded scenarios and confidence ranges", | ||
| "Execute only when trigger and risk profile align", | ||
| ].map((item) => ( | ||
| <div key={item} className="rounded-xl border border-white/10 bg-black/20 p-3 text-sm text-zinc-200"> | ||
| {item} | ||
| </div> | ||
| ))} | ||
| </div> | ||
|
|
||
| <div className="mt-6 flex flex-wrap gap-2"> | ||
| <TrackedCtaLink | ||
| href="/ai-hub" | ||
| conversionId="open_ai_chat" | ||
| surface="seo:beginner_ai_crypto" | ||
| conversionContext={{ placement: "hero", variant: "start_ai_hub", audience: "all" }} | ||
| className="rounded-full border border-cyan-300/40 bg-cyan-500/20 px-4 py-2 text-xs font-semibold text-cyan-100 hover:bg-cyan-500/30" | ||
| > | ||
| Start in AI Hub | ||
| </TrackedCtaLink> | ||
| <TrackedCtaLink | ||
| href="/blog/automated-trading-strategies-2026" | ||
| conversionId="open_service_catalog" | ||
| surface="seo:beginner_ai_crypto" | ||
| conversionContext={{ placement: "hero", variant: "learn_strategy", audience: "all" }} | ||
| className="rounded-full border border-white/20 bg-white/10 px-4 py-2 text-xs font-semibold text-zinc-100 hover:bg-white/15" | ||
| > | ||
| Read Strategy Guide | ||
| </TrackedCtaLink> | ||
| </div> | ||
| </section> | ||
| </main> | ||
| </div> | ||
| ); | ||
| redirect("/crypto-project"); | ||
| } |
| import { redirect } from "next/navigation"; | ||
|
|
||
| export default function IntelligenceCryptoFlowPage() { | ||
| return ( | ||
| <div className="min-h-screen bg-gradient-to-b from-gray-950 via-gray-900 to-black"> | ||
|
|
||
| <main className="max-w-7xl mx-auto px-4 sm:px-6 py-8 sm:py-10"> | ||
| <IntelligencePageShell | ||
| kicker="Crypto Layer" | ||
| title="Crypto Flow Intelligence" | ||
| description="Unify pair-level directional flow across major chain ecosystems with consistent confidence scoring." | ||
| quickLinks={[ | ||
| { label: "Overview", href: "/intelligence" }, | ||
| { label: "Flow Tape", href: "/intelligence/flow" }, | ||
| { label: "Calculator", href: "/intelligence/calculator" }, | ||
| ]} | ||
| > | ||
| <CryptoFlowPanel /> | ||
| </IntelligencePageShell> | ||
| </main> | ||
| </div> | ||
| ); | ||
| redirect("/crypto-project"); | ||
| } |
| import { redirect } from "next/navigation"; | ||
|
|
||
| export default function TradingPage() { | ||
| return ( | ||
| <div className="min-h-screen bg-gradient-to-b from-gray-950 via-gray-900 to-black"> | ||
|
|
||
|
|
||
| <main className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-12"> | ||
| {/* Hub header */} | ||
| <div className="mb-10"> | ||
| <h1 className="text-2xl sm:text-3xl md:text-4xl font-bold bg-gradient-to-r from-[#00FF41] to-[#39FF14] text-transparent bg-clip-text mb-3"> | ||
| TradeHax AI Trading Platform | ||
| </h1> | ||
| <p className="text-sm sm:text-base text-gray-400 max-w-2xl"> | ||
| Five production-grade AI tools working together — from sentiment analysis to live portfolio tracking, strategy building, backtesting, and full signal explainability. | ||
| </p> | ||
| </div> | ||
|
|
||
| {/* Feature navigation grid */} | ||
| <div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4 mb-14"> | ||
| {FEATURES.map(({ href, icon: Icon, title, description, badge }) => ( | ||
| <Link | ||
| key={href} | ||
| href={href} | ||
| className="group relative rounded-2xl border border-slate-700/30 bg-slate-800/20 p-6 transition-all duration-200 hover:border-cyan-500/40 hover:bg-slate-800/40 hover:shadow-[0_0_20px_rgba(0,255,65,0.07)]" | ||
| > | ||
| {badge && ( | ||
| <span className="absolute top-4 right-4 rounded-full border border-green-500/30 bg-green-500/10 px-2 py-0.5 text-[10px] font-semibold uppercase tracking-widest text-green-400"> | ||
| {badge} | ||
| </span> | ||
| )} | ||
| <div className="mb-3 inline-flex rounded-lg border border-cyan-500/20 bg-cyan-500/10 p-2.5 text-cyan-400 transition group-hover:border-cyan-500/40 group-hover:bg-cyan-500/20"> | ||
| <Icon className="w-5 h-5" /> | ||
| </div> | ||
| <h2 className="text-base font-semibold text-slate-100 mb-1.5 group-hover:text-white transition"> | ||
| {title} | ||
| </h2> | ||
| <p className="text-xs leading-relaxed text-slate-400 group-hover:text-slate-300 transition"> | ||
| {description} | ||
| </p> | ||
| </Link> | ||
| ))} | ||
| </div> | ||
|
|
||
| {/* Bot dashboard */} | ||
| <div className="mb-4 flex items-center gap-2"> | ||
| <Bot className="w-5 h-5 text-cyan-400" /> | ||
| <h2 className="text-lg font-semibold text-slate-100">Bot Dashboard</h2> | ||
| </div> | ||
| <TradehaxBotDashboard /> | ||
| </main> | ||
|
|
||
| </div> | ||
| ); | ||
| redirect("/crypto-project"); | ||
| } |
| import { redirect } from "next/navigation"; | ||
|
|
||
| /** | ||
| * /trading/strategy-builder — Visual No-Code Strategy Builder page. | ||
| */ | ||
|
|
||
| import { useState, useCallback } from "react"; | ||
| import { nanoid } from "@/lib/utils"; | ||
| import { StrategyCanvas } from "@/components/trading/strategy-builder/StrategyCanvas"; | ||
| import { StrategyToolbar, BlockTemplate, BLOCK_TEMPLATES } from "@/components/trading/strategy-builder/StrategyToolbar"; | ||
| import { StrategyPreview } from "@/components/trading/strategy-builder/StrategyPreview"; | ||
| import { serializeStrategy, deserializeStrategy } from "@/lib/trading/strategy-serializer"; | ||
| import type { StrategyBlock, StrategyDefinition } from "@/types/trading"; | ||
| import { Download, Upload, Trash2, Copy } from "lucide-react"; | ||
|
|
||
| // ─── Template Presets ───────────────────────────────────────────────────────── | ||
|
|
||
| const PRESET_NAMES = ["Conservative DCA", "Momentum Rider", "Grid Scalper", "Sentiment Surfer"] as const; | ||
| type PresetName = typeof PRESET_NAMES[number]; | ||
|
|
||
| function getBlocksByTypes(types: StrategyBlock["type"][]): StrategyBlock[] { | ||
| return types.map((t, i) => { | ||
| const tmpl = BLOCK_TEMPLATES.find((b) => b.type === t)!; | ||
| return { | ||
| id: nanoid(), | ||
| type: tmpl.type, | ||
| category: tmpl.category, | ||
| label: tmpl.label, | ||
| description: tmpl.description, | ||
| params: tmpl.defaultParams.map((p) => ({ ...p })), | ||
| position: i, | ||
| enabled: true, | ||
| isPremium: tmpl.isPremium, | ||
| }; | ||
| }); | ||
| } | ||
|
|
||
| const PRESETS: Record<PresetName, Omit<StrategyDefinition, "id" | "createdAt" | "updatedAt">> = { | ||
| "Conservative DCA": { | ||
| name: "Conservative DCA", | ||
| description: "Dollar-cost average into dips using RSI oversold signals.", | ||
| blocks: getBlocksByTypes(["rsi_threshold", "stop_loss", "take_profit", "dca_increment", "buy"]), | ||
| tags: ["dca", "conservative"], | ||
| }, | ||
| "Momentum Rider": { | ||
| name: "Momentum Rider", | ||
| description: "Ride breakouts with MACD and volume confirmation.", | ||
| blocks: getBlocksByTypes(["macd_signal", "volume_spike", "trend_filter", "buy", "trailing_stop"]), | ||
| tags: ["momentum", "breakout"], | ||
| }, | ||
| "Grid Scalper": { | ||
| name: "Grid Scalper", | ||
| description: "Scale in/out with limit orders inside a price range.", | ||
| blocks: getBlocksByTypes(["price_cross", "limit_order", "take_profit", "stop_loss"]), | ||
| tags: ["grid", "scalping"], | ||
| }, | ||
| "Sentiment Surfer": { | ||
| name: "Sentiment Surfer", | ||
| description: "Trade based on Fear & Greed index transitions.", | ||
| blocks: getBlocksByTypes(["sentiment_threshold", "buy", "take_profit", "stop_loss"]), | ||
| tags: ["sentiment", "contrarian"], | ||
| }, | ||
| }; | ||
|
|
||
| function buildPreset(name: PresetName): StrategyDefinition { | ||
| const now = new Date().toISOString(); | ||
| const template = PRESETS[name]; | ||
| const blocks = template.blocks.map((b, i) => ({ | ||
| ...b, | ||
| id: nanoid(), | ||
| position: i, | ||
| params: b.params.map((p) => ({ ...p })), | ||
| })); | ||
| return { ...template, id: nanoid(), createdAt: now, updatedAt: now, blocks }; | ||
| } | ||
|
|
||
| function emptyStrategy(): StrategyDefinition { | ||
| const now = new Date().toISOString(); | ||
| return { | ||
| id: nanoid(), | ||
| name: "My Strategy", | ||
| description: "", | ||
| blocks: [], | ||
| tags: [], | ||
| createdAt: now, | ||
| updatedAt: now, | ||
| }; | ||
| } | ||
|
|
||
| // ─── Page ───────────────────────────────────────────────────────────────────── | ||
|
|
||
| export default function StrategyBuilderPage() { | ||
| const [strategy, setStrategy] = useState<StrategyDefinition>(emptyStrategy); | ||
| const [isPremium] = useState(false); // wire to your monetization hook | ||
| const [exportMsg, setExportMsg] = useState<string | null>(null); | ||
|
|
||
| const updateStrategy = useCallback((changes: Partial<StrategyDefinition>) => { | ||
| setStrategy((prev) => ({ ...prev, ...changes, updatedAt: new Date().toISOString() })); | ||
| }, []); | ||
|
|
||
| // ── Add block ──────────────────────────────────────────────────────────── | ||
|
|
||
| const addBlock = useCallback( | ||
| (tmpl: BlockTemplate) => { | ||
| if (tmpl.isPremium && !isPremium) return; | ||
| const newBlock: StrategyBlock = { | ||
| id: nanoid(), | ||
| type: tmpl.type, | ||
| category: tmpl.category, | ||
| label: tmpl.label, | ||
| description: tmpl.description, | ||
| params: tmpl.defaultParams.map((p) => ({ ...p })), | ||
| position: strategy.blocks.length, | ||
| enabled: true, | ||
| isPremium: tmpl.isPremium, | ||
| }; | ||
| updateStrategy({ blocks: [...strategy.blocks, newBlock] }); | ||
| }, | ||
| [isPremium, strategy.blocks, updateStrategy], | ||
| ); | ||
|
|
||
| // ── Export / Import ────────────────────────────────────────────────────── | ||
|
|
||
| function handleExport() { | ||
| const json = serializeStrategy(strategy); | ||
| const blob = new Blob([json], { type: "application/json" }); | ||
| const url = URL.createObjectURL(blob); | ||
| const a = document.createElement("a"); | ||
| a.href = url; | ||
| const safeName = strategy.name.replace(/[^a-zA-Z0-9-]/gi, "-").toLowerCase(); | ||
| a.download = `${safeName}.json`; | ||
| a.click(); | ||
| URL.revokeObjectURL(url); | ||
| setExportMsg("Strategy exported!"); | ||
| setTimeout(() => setExportMsg(null), 2000); | ||
| } | ||
|
|
||
| function handleImport() { | ||
| const input = document.createElement("input"); | ||
| input.type = "file"; | ||
| input.accept = ".json"; | ||
| input.onchange = (e) => { | ||
| const file = (e.target as HTMLInputElement).files?.[0]; | ||
| if (!file) return; | ||
| const reader = new FileReader(); | ||
| reader.onload = (ev) => { | ||
| const parsed = deserializeStrategy(String(ev.target?.result ?? "")); | ||
| if (parsed) { | ||
| setStrategy(parsed); | ||
| setExportMsg("Strategy imported!"); | ||
| } else { | ||
| setExportMsg("Invalid strategy file."); | ||
| } | ||
| setTimeout(() => setExportMsg(null), 2500); | ||
| }; | ||
| reader.readAsText(file); | ||
| }; | ||
| input.click(); | ||
| } | ||
|
|
||
| function handleCopy() { | ||
| navigator.clipboard.writeText(serializeStrategy(strategy)).then(() => { | ||
| setExportMsg("Copied to clipboard!"); | ||
| setTimeout(() => setExportMsg(null), 2000); | ||
| }); | ||
| } | ||
|
|
||
| return ( | ||
| <main className="min-h-screen bg-background text-foreground p-4 md:p-8"> | ||
| {/* ── Header ─────────────────────────────────────────────────────────── */} | ||
| <div className="mb-6 flex flex-col sm:flex-row sm:items-center sm:justify-between gap-4"> | ||
| <div> | ||
| <h1 className="text-2xl font-bold font-display">Visual Strategy Builder</h1> | ||
| <p className="text-sm text-muted-foreground">Build no-code trading strategies with drag-and-drop blocks.</p> | ||
| </div> | ||
|
|
||
| <div className="flex flex-wrap gap-2"> | ||
| {/* Preset picker */} | ||
| <select | ||
| className="text-xs bg-muted border border-border rounded px-2 py-1.5 text-foreground" | ||
| onChange={(e) => { | ||
| if (!e.target.value) return; | ||
| setStrategy(buildPreset(e.target.value as PresetName)); | ||
| e.target.value = ""; | ||
| }} | ||
| aria-label="Load preset strategy" | ||
| defaultValue="" | ||
| > | ||
| <option value="" disabled>Load preset…</option> | ||
| {PRESET_NAMES.map((n) => ( | ||
| <option key={n} value={n}>{n}</option> | ||
| ))} | ||
| </select> | ||
|
|
||
| <button | ||
| onClick={() => updateStrategy({ blocks: [], updatedAt: new Date().toISOString() })} | ||
| className="flex items-center gap-1.5 text-xs px-3 py-1.5 rounded border border-border hover:bg-muted/60 transition-colors" | ||
| aria-label="Clear all blocks" | ||
| > | ||
| <Trash2 className="w-3.5 h-3.5" /> Clear | ||
| </button> | ||
|
|
||
| <button | ||
| onClick={handleImport} | ||
| className="flex items-center gap-1.5 text-xs px-3 py-1.5 rounded border border-border hover:bg-muted/60 transition-colors" | ||
| > | ||
| <Upload className="w-3.5 h-3.5" /> Import | ||
| </button> | ||
|
|
||
| <button | ||
| onClick={handleExport} | ||
| className="flex items-center gap-1.5 text-xs px-3 py-1.5 rounded border border-border hover:bg-muted/60 transition-colors" | ||
| > | ||
| <Download className="w-3.5 h-3.5" /> Export | ||
| </button> | ||
|
|
||
| <button | ||
| onClick={handleCopy} | ||
| className="flex items-center gap-1.5 text-xs px-3 py-1.5 rounded border border-border hover:bg-muted/60 transition-colors" | ||
| > | ||
| <Copy className="w-3.5 h-3.5" /> Copy JSON | ||
| </button> | ||
|
|
||
| {exportMsg && ( | ||
| <span className="text-xs text-green-400 self-center" role="status">{exportMsg}</span> | ||
| )} | ||
| </div> | ||
| </div> | ||
|
|
||
| {/* Strategy name input */} | ||
| <div className="mb-4 flex gap-3 items-center"> | ||
| <input | ||
| type="text" | ||
| value={strategy.name} | ||
| onChange={(e) => updateStrategy({ name: e.target.value })} | ||
| className="flex-1 max-w-xs text-sm rounded-lg border border-border bg-muted/30 px-3 py-1.5 text-foreground focus:outline-none focus:ring-1 focus:ring-ring" | ||
| aria-label="Strategy name" | ||
| placeholder="Strategy name" | ||
| /> | ||
| <input | ||
| type="text" | ||
| value={strategy.description} | ||
| onChange={(e) => updateStrategy({ description: e.target.value })} | ||
| className="flex-1 text-sm rounded-lg border border-border bg-muted/30 px-3 py-1.5 text-foreground focus:outline-none focus:ring-1 focus:ring-ring" | ||
| aria-label="Strategy description" | ||
| placeholder="Optional description…" | ||
| /> | ||
| </div> | ||
|
|
||
| {/* ── Layout: toolbar | canvas | preview ─────────────────────────────── */} | ||
| <div className="flex flex-col lg:flex-row gap-6"> | ||
| {/* Block palette */} | ||
| <StrategyToolbar isPremium={isPremium} onAddBlock={addBlock} /> | ||
|
|
||
| {/* Canvas */} | ||
| <div className="flex-1 min-w-0"> | ||
| <StrategyCanvas | ||
| blocks={strategy.blocks} | ||
| isPremium={isPremium} | ||
| onBlocksChange={(blocks) => updateStrategy({ blocks })} | ||
| /> | ||
| </div> | ||
|
|
||
| {/* Preview panel */} | ||
| <aside className="w-full lg:w-72 flex-shrink-0 rounded-xl border border-border/40 bg-muted/20 p-4 overflow-y-auto max-h-[calc(100vh-200px)]"> | ||
| <h3 className="text-sm font-semibold text-foreground mb-3">Strategy Preview</h3> | ||
| <StrategyPreview strategy={strategy} /> | ||
| </aside> | ||
| </div> | ||
| </main> | ||
| ); | ||
| export default function Page() { | ||
| redirect("/crypto-project"); | ||
| } |
| import { redirect } from "next/navigation"; | ||
|
|
||
| /** | ||
| * /trading/xai — AI Explainability (XAI) Panel page. | ||
| * Let users enter a signal or pick a preset to see a full AI explanation. | ||
| */ | ||
|
|
||
| import { useState, useCallback } from "react"; | ||
| import { Sparkles, ChevronDown } from "lucide-react"; | ||
| import { SignalExplainer } from "@/components/trading/SignalExplainer"; | ||
| import type { SignalExplanation, TradingSignal } from "@/types/trading"; | ||
|
|
||
| // ─── Preset signals ─────────────────────────────────────────────────────────── | ||
|
|
||
| interface PresetSignal { | ||
| label: string; | ||
| signal: Omit<TradingSignal, "id" | "generatedAt">; | ||
| } | ||
|
|
||
| const PRESETS: PresetSignal[] = [ | ||
| { | ||
| label: "BTC Strong Buy", | ||
| signal: { | ||
| symbol: "BTC", | ||
| action: "buy", | ||
| confidence: 0.87, | ||
| price: 68500, | ||
| targetPrice: 74000, | ||
| stopLoss: 65000, | ||
| timeframe: "4h", | ||
| source: "ai-engine", | ||
| tags: ["momentum", "on-chain"], | ||
| }, | ||
| }, | ||
| { | ||
| label: "ETH Sell Signal", | ||
| signal: { | ||
| symbol: "ETH", | ||
| action: "sell", | ||
| confidence: 0.72, | ||
| price: 3400, | ||
| targetPrice: 3100, | ||
| stopLoss: 3600, | ||
| timeframe: "1d", | ||
| source: "ai-engine", | ||
| tags: ["overbought", "resistance"], | ||
| }, | ||
| }, | ||
| { | ||
| label: "SOL Hold", | ||
| signal: { | ||
| symbol: "SOL", | ||
| action: "hold", | ||
| confidence: 0.55, | ||
| price: 145, | ||
| targetPrice: 160, | ||
| stopLoss: 130, | ||
| timeframe: "1h", | ||
| source: "ai-engine", | ||
| tags: ["neutral", "consolidation"], | ||
| }, | ||
| }, | ||
| ]; | ||
|
|
||
| // ─── Skeleton ───────────────────────────────────────────────────────────────── | ||
|
|
||
| function ExplainSkeleton() { | ||
| return ( | ||
| <div className="space-y-4 animate-pulse"> | ||
| <div className="h-20 rounded-xl bg-slate-800/50 border border-slate-700/20" /> | ||
| <div className="grid grid-cols-2 sm:grid-cols-4 gap-3"> | ||
| {[0, 1, 2, 3].map((i) => ( | ||
| <div key={i} className="h-16 rounded-lg bg-slate-800/40" /> | ||
| ))} | ||
| </div> | ||
| <div className="h-48 rounded-xl bg-slate-800/40" /> | ||
| </div> | ||
| ); | ||
| } | ||
|
|
||
| // ─── Page ───────────────────────────────────────────────────────────────────── | ||
|
|
||
| export default function XAIPage() { | ||
| const [explanation, setExplanation] = useState<SignalExplanation | null>(null); | ||
| const [loading, setLoading] = useState(false); | ||
| const [error, setError] = useState<string | null>(null); | ||
| const [activePreset, setActivePreset] = useState<string | null>(null); | ||
|
|
||
| const fetchExplanation = useCallback(async (preset: PresetSignal) => { | ||
| setActivePreset(preset.label); | ||
| setLoading(true); | ||
| setError(null); | ||
|
|
||
| try { | ||
| const res = await fetch("/api/signals/explain", { | ||
| method: "POST", | ||
| headers: { "Content-Type": "application/json" }, | ||
| body: JSON.stringify({ | ||
| ...preset.signal, | ||
| id: `preset-${Date.now()}`, | ||
| generatedAt: new Date().toISOString(), | ||
| }), | ||
| }); | ||
|
|
||
| const json = await res.json(); | ||
| if (!res.ok || !json.ok) { | ||
| throw new Error(json.error ?? "Failed to fetch explanation."); | ||
| } | ||
| setExplanation(json.data as SignalExplanation); | ||
| } catch (err) { | ||
| setError(err instanceof Error ? err.message : "Unexpected error."); | ||
| } finally { | ||
| setLoading(false); | ||
| } | ||
| }, []); | ||
|
|
||
| return ( | ||
| <div className="min-h-screen bg-gradient-to-b from-gray-950 via-gray-900 to-black"> | ||
|
|
||
|
|
||
| <main className="max-w-5xl mx-auto px-4 sm:px-6 lg:px-8 py-12"> | ||
| {/* Page header */} | ||
| <div className="mb-8"> | ||
| <h1 className="text-2xl sm:text-3xl md:text-4xl font-bold bg-gradient-to-r from-[#00FF41] to-[#39FF14] text-transparent bg-clip-text mb-2"> | ||
| AI Explainability Panel | ||
| </h1> | ||
| <p className="text-sm sm:text-base text-gray-400"> | ||
| Understand exactly why the AI generated each signal — factor weights, risk levels, and historical accuracy in full detail. | ||
| </p> | ||
| </div> | ||
|
|
||
| {/* Preset selector */} | ||
| <div className="mb-8"> | ||
| <p className="text-xs font-semibold text-slate-400 uppercase tracking-widest mb-3 flex items-center gap-1.5"> | ||
| <ChevronDown className="w-3.5 h-3.5" /> | ||
| Choose a sample signal to explain | ||
| </p> | ||
| <div className="flex flex-wrap gap-3"> | ||
| {PRESETS.map((preset) => ( | ||
| <button | ||
| key={preset.label} | ||
| type="button" | ||
| onClick={() => fetchExplanation(preset)} | ||
| disabled={loading} | ||
| aria-pressed={activePreset === preset.label} | ||
| className={`flex items-center gap-2 rounded-lg border px-4 py-2 text-sm font-medium transition-all duration-200 disabled:opacity-50 ${ | ||
| activePreset === preset.label | ||
| ? "border-cyan-500/60 bg-cyan-500/15 text-cyan-300" | ||
| : "border-slate-700/40 bg-slate-800/30 text-slate-300 hover:border-cyan-500/30 hover:bg-cyan-500/5" | ||
| }`} | ||
| > | ||
| <Sparkles className="w-3.5 h-3.5" /> | ||
| {preset.label} | ||
| </button> | ||
| ))} | ||
| </div> | ||
| </div> | ||
|
|
||
| {/* Error */} | ||
| {error && ( | ||
| <div className="mb-6 rounded-lg border border-red-500/30 bg-red-500/10 px-4 py-3 text-sm text-red-400"> | ||
| {error} | ||
| </div> | ||
| )} | ||
|
|
||
| {/* Results */} | ||
| {loading && <ExplainSkeleton />} | ||
|
|
||
| {!loading && explanation && ( | ||
| <SignalExplainer explanation={explanation} /> | ||
| )} | ||
|
|
||
| {!loading && !explanation && !error && ( | ||
| <div className="rounded-2xl border border-dashed border-slate-700/40 bg-slate-900/20 p-16 text-center"> | ||
| <Sparkles className="w-8 h-8 text-slate-600 mx-auto mb-3" /> | ||
| <p className="text-slate-500 text-sm"> | ||
| Select a sample signal above to see the full AI explanation. | ||
| </p> | ||
| </div> | ||
| )} | ||
| </main> | ||
|
|
||
| </div> | ||
| ); | ||
| export default function Page() { | ||
| redirect("/crypto-project"); | ||
| } |
| import { redirect } from "next/navigation"; | ||
|
|
||
| /** | ||
| * /trading/backtest — Backtesting Sandbox page. | ||
| */ | ||
|
|
||
| import { BacktestForm } from "@/components/trading/backtest/BacktestForm"; | ||
| import { BacktestResults } from "@/components/trading/backtest/BacktestResults"; | ||
| import type { BacktestConfig, BacktestResult } from "@/types/trading"; | ||
| import { useState } from "react"; | ||
| import useSWR from "swr"; | ||
|
|
||
| type PhaseStatusResponse = { | ||
| ok: boolean; | ||
| status?: { | ||
| complete?: boolean; | ||
| confidence?: number; | ||
| }; | ||
| }; | ||
|
|
||
| const fetcher = async (url: string): Promise<PhaseStatusResponse> => { | ||
| const response = await fetch(url, { cache: "no-store" }); | ||
| if (!response.ok) { | ||
| throw new Error(`Failed to fetch ${url}`); | ||
| } | ||
| return (await response.json()) as PhaseStatusResponse; | ||
| }; | ||
|
|
||
| // ─── Skeleton loader ────────────────────────────────────────────────────────── | ||
|
|
||
| function Skeleton() { | ||
| return ( | ||
| <div className="space-y-4 animate-pulse" aria-busy="true" aria-label="Loading backtest results"> | ||
| <div className="grid grid-cols-2 sm:grid-cols-4 gap-3"> | ||
| {Array.from({ length: 8 }).map((_, i) => ( | ||
| <div key={i} className="h-20 rounded-lg bg-muted/30" /> | ||
| ))} | ||
| </div> | ||
| <div className="h-10 w-64 rounded bg-muted/30" /> | ||
| <div className="h-64 rounded-xl bg-muted/30" /> | ||
| </div> | ||
| ); | ||
| } | ||
|
|
||
| // ─── Page ───────────────────────────────────────────────────────────────────── | ||
|
|
||
| export default function BacktestPage() { | ||
| const { data: phaseStatus } = useSWR("/api/phase03/status", fetcher, { | ||
| refreshInterval: 30_000, | ||
| dedupingInterval: 10_000, | ||
| revalidateOnFocus: false, | ||
| }); | ||
| const [result, setResult] = useState<BacktestResult | null>(null); | ||
| const [loading, setLoading] = useState(false); | ||
| const [error, setError] = useState<string | null>(null); | ||
|
|
||
| async function handleRun(config: BacktestConfig) { | ||
| setLoading(true); | ||
| setError(null); | ||
|
|
||
| try { | ||
| const res = await fetch("/api/backtest/run", { | ||
| method: "POST", | ||
| headers: { "Content-Type": "application/json" }, | ||
| body: JSON.stringify(config), | ||
| }); | ||
|
|
||
| if (!res.ok) { | ||
| const body = await res.json().catch(() => ({})); | ||
| throw new Error((body as { error?: string }).error ?? `HTTP ${res.status}`); | ||
| } | ||
|
|
||
| const json = await res.json() as { ok: boolean; data: BacktestResult }; | ||
| setResult(json.data); | ||
| } catch (err) { | ||
| setError(err instanceof Error ? err.message : "Backtest failed."); | ||
| } finally { | ||
| setLoading(false); | ||
| } | ||
| } | ||
|
|
||
| return ( | ||
| <main className="min-h-screen bg-background text-foreground p-4 md:p-8"> | ||
| {/* Header */} | ||
| <div className="mb-6"> | ||
| <h1 className="text-2xl font-bold font-display">Backtesting Sandbox</h1> | ||
| <p className="text-sm text-muted-foreground mt-1"> | ||
| Simulate your trading strategy against historical price data. Powered by RSI-based signal generation. | ||
| </p> | ||
| {phaseStatus?.ok && ( | ||
| <p className="text-xs text-muted-foreground mt-2"> | ||
| System status: {phaseStatus.status?.complete ? "ready" : "warming"} | ||
| </p> | ||
| )} | ||
| </div> | ||
|
|
||
| {/* Config form */} | ||
| <div className="mb-8 rounded-xl border border-border/40 bg-muted/10 p-5"> | ||
| <h2 className="text-sm font-semibold text-foreground mb-4">Configuration</h2> | ||
| <BacktestForm onSubmit={handleRun} loading={loading} /> | ||
| </div> | ||
|
|
||
| {/* Error state */} | ||
| {error && ( | ||
| <div className="mb-4 rounded-lg border border-red-500/30 bg-red-500/10 p-3 text-sm text-red-400" role="alert"> | ||
| {error} | ||
| </div> | ||
| )} | ||
|
|
||
| {/* Results */} | ||
| {loading && <Skeleton />} | ||
| {!loading && result && ( | ||
| <div className="rounded-xl border border-border/40 bg-muted/10 p-5"> | ||
| <div className="flex items-center justify-between mb-5 flex-wrap gap-2"> | ||
| <h2 className="text-sm font-semibold text-foreground"> | ||
| Results — {result.config.symbol} / {result.config.timeRange} | ||
| </h2> | ||
| <span className="text-xs text-muted-foreground"> | ||
| Completed {new Date(result.completedAt).toLocaleTimeString()} | ||
| </span> | ||
| </div> | ||
| <BacktestResults result={result} /> | ||
| </div> | ||
| )} | ||
|
|
||
| {!loading && !result && !error && ( | ||
| <div className="flex flex-col items-center justify-center h-48 text-muted-foreground text-sm gap-2 rounded-xl border-2 border-dashed border-border/30"> | ||
| <span className="text-3xl">📈</span> | ||
| <p>Configure and run a backtest to see results here.</p> | ||
| </div> | ||
| )} | ||
| </main> | ||
| ); | ||
| export default function Page() { | ||
| redirect("/crypto-project"); | ||
| } |
| import { redirect } from "next/navigation"; | ||
|
|
||
| export default function PolymarketPage() { | ||
| return <PolymarketClientPage />; | ||
| redirect("/crypto-project"); | ||
| } |
All crypto/trading/Web3 subject matter was scattered across multiple pages, components, API routes, and the global layout ticker — including surfacing on the homepage. This PR consolidates everything under
/crypto-projectand removes dead code.Homepage & Global Layout
MarketTicker(BTC/ETH/SOL/AVAX ticker tape) now renders only whenpathname === '/crypto-project'; previously showed site-wideLiveActivitymarket-sentiment signal entry replaced with a neutral system message/crypto-project— Rebuilt as product landing pageSections: Hero → Capabilities (6 modules) → Why/Edge → Roadmap (Now/Next/Later) → FAQ + Risk Disclosure → CTAs
Old crypto routes → 301 redirects to
/crypto-project/intelligence/crypto-flow,/trading/*(all sub-pages),/web3-token-roadmap-consulting,/beginner-ai-crypto-trading-assistant,/polymarketapp/intelligence/page.tsxRemoved "Crypto Flow" quick-link, metric card (
cryptoNotional24hUsd), and module card. Cleaned crypto-specific copy from descriptions and metadata keywords.Collateral cleanups
app/onboarding/page.tsx:/tradinglink →/crypto-projectapp/ai-hub/page.tsx: removed crypto trading assistant FAQ, web3 keyword metadata, and Web3 Roadmap Guide CTAapp/sitemap.ts: removed/trading,/beginner-ai-crypto-trading-assistant,/web3-token-roadmap-consulting; added/crypto-projectDead code deleted (~10,000 lines)
components/trading/*components/intelligence/CryptoFlowPanel.tsxlib/trading/*hooks/use-portfolio.ts,use-sentiment-stream.tsapp/api/intelligence/crypto-flow,backtest/run,portfolio/aggregate,sentiment,signals/explain,cron/trading/signal-cadence, alltrading/*routes (bot + signal)lib/intelligence/discord-signals.tstypes/trading.tsOriginal prompt
Goal
DarkModder33/main(base branch:main).app/page.tsx) contains the system timeline but contains no crypto-related subject matter.app/crypto-project/page.tsxpage ("Crypto Project" page).Scope details
/crypto-project./crypto-project(examples observed:/intelligence/crypto-flow,/trading/portfolio,/web3-token-roadmap-consulting, plus anything else found), either:/crypto-projectif route removal would break internal links./crypto-projectas the single crypto destination.app/page.tsx) and remove it.MarketTickerinapp/layout.tsx) to ensure they do not surface crypto site-wide. If they do, restrict crypto-specific visuals to the/crypto-projectroute./crypto-projectpage professionallyapp/crypto-project/page.tsxas a polished, professionally structured product page for the crypto project.app/api/intelligence/crypto-flow/route.tsand any others) if no longer referenced.components/trading/*if not used.lib/trading/*if not used.types/trading.tsif only used by deleted routes.Notes
DarkModder33/mainmainThe following is the prior conversation context from the user's chat exploration (may be truncated):
User: the system timeline on the firstpage and all crypto related subject matter should be on the crypto project page only. inspect all pages and content on tradehax.net and its subpages . Gather all crypto related subject matter and reconstruct it all of an updated, professionally structured webpage. Delete all frontend and backend code that is not neccesarry when complete
Assistant: I can do this, but I need two clarifications before I touch anything because your request involves (1) inspecting a live website and (2) deleting code in a repo:
Where is the code hosted (exact GitHub repo)?
The URL you provided (
DarkModder33/main/pulls) isn’t a valid GitHub repository path (GitHub repos areowner/repo, e.g.DarkModder33/tradehax).Please paste the real repo URL, e.g.:
https://github.com/DarkModder33/<repo>/pullsor justDarkModder33/<repo>Confirm what you want me to produce on GitHub:
Do you want me to open a pull request with:
If yes, tell me the base branch to target (usually
main) and whether I’m allowed to delete files outright or if you prefer I deprecate/redirect them.Also, to “inspect all pages and content on tradehax.net and its subpages”, I need either:
Reply with:
owner/repo(or the full GitHub URL)mainor otherOnce I have that, I’ll: locate every crypto-related mention, move it to a dedicated crypto page, rewrite/restructure that page pr...
This pull request was created from Copilot chat.
Summary by Sourcery
Consolidate all crypto and trading functionality into a single /crypto-project landing page while removing or redirecting legacy crypto/trading routes and deleting the underlying trading front- and back-end code.
New Features:
Enhancements:
Chores: