196 lines
7.0 KiB
TypeScript
196 lines
7.0 KiB
TypeScript
'use client'
|
|
|
|
import Link from 'next/link'
|
|
import { ArrowLeft } from 'lucide-react'
|
|
import { useState } from 'react'
|
|
import { checkSymbol, addUserInterest } from '@/lib/userInterestsApi'
|
|
|
|
type ResultState = { type: 'success' | 'error' | 'loading' | null; message: string }
|
|
|
|
export default function AddItem() {
|
|
const [activeTab, setActiveTab] = useState<'symbol' | 'topic'>('symbol')
|
|
const [symbolInput, setSymbolInput] = useState('')
|
|
const [topicInput, setTopicInput] = useState('')
|
|
const [symbolResult, setSymbolResult] = useState<ResultState>({ type: null, message: '' })
|
|
const [topicResult, setTopicResult] = useState<ResultState>({ type: null, message: '' })
|
|
|
|
const handleAddSymbol = async () => {
|
|
const trimmed = symbolInput.trim()
|
|
if (!trimmed) return
|
|
|
|
setSymbolResult({ type: 'loading', message: 'Verifying symbol...' })
|
|
|
|
try {
|
|
// Step 1: Check if symbol is valid
|
|
const checkResult = await checkSymbol(trimmed)
|
|
|
|
if (!checkResult.found) {
|
|
setSymbolResult({
|
|
type: 'error',
|
|
message: checkResult.message,
|
|
})
|
|
return
|
|
}
|
|
|
|
// Step 2: Add the symbol
|
|
const addResult = await addUserInterest('symbol', trimmed)
|
|
setSymbolResult({
|
|
type: 'success',
|
|
message: `${trimmed.toUpperCase()} has been successfully added!`,
|
|
})
|
|
setSymbolInput('')
|
|
} catch (err) {
|
|
setSymbolResult({
|
|
type: 'error',
|
|
message: err instanceof Error ? err.message : 'Failed to add symbol',
|
|
})
|
|
}
|
|
}
|
|
|
|
const handleAddTopic = async () => {
|
|
const trimmed = topicInput.trim()
|
|
if (!trimmed) return
|
|
|
|
setTopicResult({ type: 'loading', message: 'Adding topic...' })
|
|
|
|
try {
|
|
await addUserInterest('topic', trimmed)
|
|
setTopicResult({
|
|
type: 'success',
|
|
message: `${trimmed} has been added to your interests list!`,
|
|
})
|
|
setTopicInput('')
|
|
} catch (err) {
|
|
setTopicResult({
|
|
type: 'error',
|
|
message: err instanceof Error ? err.message : 'Failed to add topic',
|
|
})
|
|
}
|
|
}
|
|
|
|
return (
|
|
<div className="h-full flex flex-col">
|
|
{/* Header */}
|
|
<div className="bg-background border-b border-border px-6 py-4 flex items-center gap-4">
|
|
<Link href="/interests" className="p-2 hover:bg-secondary transition-colors">
|
|
<ArrowLeft size={20} />
|
|
</Link>
|
|
<h1 className="text-2xl font-bold">Add Item</h1>
|
|
</div>
|
|
|
|
{/* Content */}
|
|
<div className="flex-1 overflow-y-auto p-6">
|
|
<div className="max-w-md space-y-6">
|
|
{/* Tabs */}
|
|
<div className="flex gap-2 border-b border-border">
|
|
<button
|
|
onClick={() => {
|
|
setActiveTab('symbol')
|
|
setSymbolResult({ type: null, message: '' })
|
|
}}
|
|
className={`px-6 py-3 border-b-2 font-medium transition-colors ${
|
|
activeTab === 'symbol'
|
|
? 'border-primary text-foreground'
|
|
: 'border-transparent text-muted-foreground hover:text-foreground'
|
|
}`}
|
|
>
|
|
Add Symbol
|
|
</button>
|
|
<button
|
|
onClick={() => {
|
|
setActiveTab('topic')
|
|
setTopicResult({ type: null, message: '' })
|
|
}}
|
|
className={`px-6 py-3 border-b-2 font-medium transition-colors ${
|
|
activeTab === 'topic'
|
|
? 'border-primary text-foreground'
|
|
: 'border-transparent text-muted-foreground hover:text-foreground'
|
|
}`}
|
|
>
|
|
Add Topic
|
|
</button>
|
|
</div>
|
|
|
|
{/* Add Symbol Tab */}
|
|
{activeTab === 'symbol' && (
|
|
<div className="space-y-4">
|
|
<div className="space-y-3">
|
|
<label className="block text-sm font-medium">Symbol:</label>
|
|
<input
|
|
type="text"
|
|
placeholder="Enter stock symbol (e.g., AAPL, MSFT)"
|
|
value={symbolInput}
|
|
onChange={(e) => setSymbolInput(e.target.value)}
|
|
disabled={symbolResult.type === 'loading'}
|
|
className="w-full border border-border bg-input text-foreground p-4 text-base disabled:opacity-60"
|
|
/>
|
|
</div>
|
|
|
|
<button
|
|
onClick={handleAddSymbol}
|
|
disabled={!symbolInput.trim() || symbolResult.type === 'loading'}
|
|
className="w-full bg-primary text-primary-foreground p-4 font-medium hover:bg-blue-700 transition-colors disabled:opacity-50 disabled:cursor-not-allowed text-base"
|
|
>
|
|
{symbolResult.type === 'loading' ? 'Verifying...' : 'ADD'}
|
|
</button>
|
|
|
|
{symbolResult.type && (
|
|
<div
|
|
className={`p-4 text-sm font-medium ${
|
|
symbolResult.type === 'success'
|
|
? 'bg-positive/10 text-positive border border-positive'
|
|
: symbolResult.type === 'error'
|
|
? 'bg-negative/10 text-negative border border-negative'
|
|
: 'bg-yellow-400/10 text-yellow-600 border border-yellow-400'
|
|
}`}
|
|
>
|
|
{symbolResult.message}
|
|
</div>
|
|
)}
|
|
</div>
|
|
)}
|
|
|
|
{/* Add Topic Tab */}
|
|
{activeTab === 'topic' && (
|
|
<div className="space-y-4">
|
|
<div className="space-y-3">
|
|
<label className="block text-sm font-medium">Topic:</label>
|
|
<input
|
|
type="text"
|
|
placeholder="Enter topic name (e.g., AI, Healthcare, Energy)"
|
|
value={topicInput}
|
|
onChange={(e) => setTopicInput(e.target.value)}
|
|
disabled={topicResult.type === 'loading'}
|
|
className="w-full border border-border bg-input text-foreground p-4 text-base disabled:opacity-60"
|
|
/>
|
|
</div>
|
|
|
|
<button
|
|
onClick={handleAddTopic}
|
|
disabled={!topicInput.trim() || topicResult.type === 'loading'}
|
|
className="w-full bg-primary text-primary-foreground p-4 font-medium hover:bg-blue-700 transition-colors disabled:opacity-50 disabled:cursor-not-allowed text-base"
|
|
>
|
|
{topicResult.type === 'loading' ? 'Adding...' : 'ADD'}
|
|
</button>
|
|
|
|
{topicResult.type && (
|
|
<div
|
|
className={`p-4 text-sm font-medium ${
|
|
topicResult.type === 'success'
|
|
? 'bg-positive/10 text-positive border border-positive'
|
|
: topicResult.type === 'error'
|
|
? 'bg-negative/10 text-negative border border-negative'
|
|
: 'bg-yellow-400/10 text-yellow-600 border border-yellow-400'
|
|
}`}
|
|
>
|
|
{topicResult.message}
|
|
</div>
|
|
)}
|
|
</div>
|
|
)}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|