From 8e047cd9d0f6f36a1d793de51fda22c7f22e2d01 Mon Sep 17 00:00:00 2001 From: 0zzy4 Date: Sun, 31 May 2026 16:41:23 -0400 Subject: [PATCH 1/2] feature: replace hardcoded search with real API calls --- frontend/app/page.tsx | 511 ++-- frontend/components/VocabularyCard.tsx | 425 +-- frontend/lib/api.ts | 247 +- frontend/package-lock.json | 3322 ++++++++++++------------ 4 files changed, 2249 insertions(+), 2256 deletions(-) diff --git a/frontend/app/page.tsx b/frontend/app/page.tsx index 1495627..1b6defc 100644 --- a/frontend/app/page.tsx +++ b/frontend/app/page.tsx @@ -1,257 +1,254 @@ -'use client' - -import { useState } from 'react' -import { motion, AnimatePresence } from 'framer-motion' -import Navigation from '@/components/Navigation' -import VocabularyCard from '@/components/VocabularyCard' -import ChatAssistant from '@/components/ChatAssistant' - -export default function LookupPage() { - const [searchQuery, setSearchQuery] = useState('') - const [selectedLanguage, setSelectedLanguage] = useState('Spanish') - const [searchResult, setSearchResult] = useState(null) - const [isSearching, setIsSearching] = useState(false) - const [showChat, setShowChat] = useState(false) - - const languages = ['Spanish', 'French', 'German', 'Italian', 'Portuguese', 'Japanese', 'Korean', 'Mandarin'] - - const handleSearch = async () => { - if (!searchQuery.trim()) return - - setIsSearching(true) - - // Simulate API call - setTimeout(() => { - setSearchResult({ - word: searchQuery, - language: selectedLanguage, - partOfSpeech: 'verb', - definitions: [ - 'To move or go from one place to another', - 'To make a journey, especially of some length or abroad', - 'To move or proceed in a particular direction' - ], - examples: [ - 'We plan to travel to Europe next summer for three weeks.', - 'She travels frequently for work, visiting different cities each month.', - 'Light travels faster than sound through different mediums.' - ], - relatedWords: ['journey', 'voyage', 'trip', 'trek', 'wander', 'roam'] - }) - setIsSearching(false) - }, 1200) - } - - const handleSave = () => { - alert('Card saved to your collection!') - } - - return ( -
- - -
-
- {/* Hero Section */} - - -
- 🔍 -
-
- -

- Master Every Word -

-

- Search any vocabulary word and get instant, comprehensive notes with definitions, examples, and context—auto-populated by AI. -

-
- - {/* Search Section */} - - {/* Language Selector */} -
- -
- {languages.map((lang) => ( - setSelectedLanguage(lang)} - className={`px-5 py-2 rounded-full font-medium transition-all duration-300 ${ - selectedLanguage === lang - ? 'bg-gradient-to-r from-terracotta to-ochre text-white shadow-md' - : 'bg-sand text-sage hover:bg-sage/20' - }`} - whileHover={{ scale: 1.05 }} - whileTap={{ scale: 0.95 }} - > - {lang} - - ))} -
-
- - {/* Search Input */} -
-
- setSearchQuery(e.target.value)} - onKeyPress={(e) => e.key === 'Enter' && handleSearch()} - placeholder="Enter a word to look up..." - className="input-field pl-12 text-lg" - /> -
- - - -
-
- - - {isSearching ? ( - <> - - Searching... - - ) : ( - <> - Search - - - - - )} - -
- - {/* Quick Tips */} - -

- 💡 - - Tip: After searching, you can ask our AI assistant about nuances, usage patterns, and contextual differences. - -

-
-
- - {/* Search Results */} - - {searchResult && ( - - - - {/* Action Buttons */} - - setShowChat(true)} - className="btn-secondary flex items-center gap-2" - whileHover={{ scale: 1.05 }} - whileTap={{ scale: 0.95 }} - > - - - - Ask About Nuances - - - setSearchResult(null)} - className="px-6 py-3 rounded-full font-medium border-2 border-sand text-sage hover:border-sage hover:bg-sage hover:text-white transition-all duration-300" - whileHover={{ scale: 1.05 }} - whileTap={{ scale: 0.95 }} - > - New Search - - - - )} - - - {/* Empty State */} - {!searchResult && !isSearching && ( - -
- 📚 -
-

- Ready to explore? -

-

- Enter a word above to get started with your vocabulary mastery journey. -

-
- )} -
-
- - {/* Chat Assistant Modal */} - - {showChat && searchResult && ( - setShowChat(false)} - /> - )} - -
- ) -} +'use client' +import { apiClient } from '@/lib/api' + +import { useState } from 'react' +import { motion, AnimatePresence } from 'framer-motion' +import Navigation from '@/components/Navigation' +import VocabularyCard from '@/components/VocabularyCard' +import ChatAssistant from '@/components/ChatAssistant' + +export default function LookupPage() { + const [searchQuery, setSearchQuery] = useState('') + const [selectedLanguage, setSelectedLanguage] = useState('Spanish') + const [searchResult, setSearchResult] = useState(null) + const [isSearching, setIsSearching] = useState(false) + const [showChat, setShowChat] = useState(false) + +const languageCodes: Record = { + 'Spanish': 'es', 'French': 'fr', 'German': 'de', 'Italian': 'it', + 'Portuguese': 'pt', 'Japanese': 'ja', 'Korean': 'ko', 'Mandarin': 'zh' +} + + const handleSearch = async () => { + if (!searchQuery.trim()) return + setIsSearching(true) + try { + const data = await apiClient.lookup({ lang: languageCodes[selectedLanguage], lemma: searchQuery.trim() }) + const card = data.card + setSearchResult({ + word: card.lemma || searchQuery, + language: selectedLanguage, + partOfSpeech: card.partOfSpeech, + definitions: [card.shortDefinition], + examples: card.examples.map((e: { src: string; tgt: string }) => ({ src: e.src, tgt: e.tgt })), + relatedWords: card.relatedWords || [] + }) + } catch { + alert('Word not found. Try another word.') + } finally { + setIsSearching(false) + } + } + const handleSave = () => { + alert('Card saved to your collection!') + } + + return ( +
+ + +
+
+ {/* Hero Section */} + + +
+ 🔍 +
+
+ +

+ Master Every Word +

+

+ Search any vocabulary word and get instant, comprehensive notes with definitions, examples, and context—auto-populated by AI. +

+
+ + {/* Search Section */} + + {/* Language Selector */} +
+ +
+ {Object.keys(languageCodes).map((lang) => ( + setSelectedLanguage(lang)} + className={`px-5 py-2 rounded-full font-medium transition-all duration-300 ${ + selectedLanguage === lang + ? 'bg-gradient-to-r from-terracotta to-ochre text-white shadow-md' + : 'bg-sand text-sage hover:bg-sage/20' + }`} + whileHover={{ scale: 1.05 }} + whileTap={{ scale: 0.95 }} + > + {lang} + + ))} +
+
+ + {/* Search Input */} +
+
+ setSearchQuery(e.target.value)} + onKeyPress={(e) => e.key === 'Enter' && handleSearch()} + placeholder="Enter a word to look up..." + className="input-field pl-12 text-lg" + /> +
+ + + +
+
+ + + {isSearching ? ( + <> + + Searching... + + ) : ( + <> + Search + + + + + )} + +
+ + {/* Quick Tips */} + +

+ 💡 + + Tip: After searching, you can ask our AI assistant about nuances, usage patterns, and contextual differences. + +

+
+
+ + {/* Search Results */} + + {searchResult && ( + + ({ src: e.src, tgt: e.tgt }))} + relatedWords={searchResult.relatedWords} + partOfSpeech={searchResult.partOfSpeech} + onSave={handleSave} + /> + + {/* Action Buttons */} + + setShowChat(true)} + className="btn-secondary flex items-center gap-2" + whileHover={{ scale: 1.05 }} + whileTap={{ scale: 0.95 }} + > + + + + Ask About Nuances + + + setSearchResult(null)} + className="px-6 py-3 rounded-full font-medium border-2 border-sand text-sage hover:border-sage hover:bg-sage hover:text-white transition-all duration-300" + whileHover={{ scale: 1.05 }} + whileTap={{ scale: 0.95 }} + > + New Search + + + + )} + + + {/* Empty State */} + {!searchResult && !isSearching && ( + +
+ 📚 +
+

+ Ready to explore? +

+

+ Enter a word above to get started with your vocabulary mastery journey. +

+
+ )} +
+
+ + {/* Chat Assistant Modal */} + + {showChat && searchResult && ( + setShowChat(false)} + /> + )} + +
+ ) +} diff --git a/frontend/components/VocabularyCard.tsx b/frontend/components/VocabularyCard.tsx index 17f870b..053a709 100644 --- a/frontend/components/VocabularyCard.tsx +++ b/frontend/components/VocabularyCard.tsx @@ -1,211 +1,214 @@ -'use client' - -import { motion } from 'framer-motion' -import { useState } from 'react' - -interface VocabularyCardProps { - word: string - language: string - definitions: string[] - examples: string[] - relatedWords: string[] - partOfSpeech?: string - onSave?: () => void - isPreview?: boolean -} - -export default function VocabularyCard({ - word, - language, - definitions, - examples, - relatedWords, - partOfSpeech, - onSave, - isPreview = false -}: VocabularyCardProps) { - const [notes, setNotes] = useState('') - const [showNotes, setShowNotes] = useState(false) - - return ( - - {/* Header */} -
-
-
- - {word} - - {partOfSpeech && ( - - {partOfSpeech} - - )} -
-

- {language} -

-
- - {!isPreview && onSave && ( - - - - - Save Card - - )} -
- - {/* Definitions */} - -

- - 📖 - - Definitions -

-
    - {definitions.map((def, idx) => ( - - - {idx + 1}. - - {def} - - ))} -
-
- - {/* Examples */} - -

- - 💬 - - Example Sentences -

-
- {examples.map((example, idx) => ( - -

- "{example}" -

-
- ))} -
-
- - {/* Related Words */} - -

- - 🔗 - - Related Words -

-
- {relatedWords.map((word, idx) => ( - - {word} - - ))} -
-
- - {/* Personal Notes Section */} - {!isPreview && ( - - - - {showNotes && ( - -