DEV Community

Cover image for AI Flashcard: NextJs (Basic)
Taki
Taki

Posted on

AI Flashcard: NextJs (Basic)

1. Create a FlashCard Component

Create a file called components/FlashCard.tsx:

import React from 'react'; export interface FlashCard { phrase: string; meaning: string; breakdown: string[]; simpleMeaning: string; usageContext: string; examples: { sentence: string; explanation: string; }[]; similarPhrases: string[]; tip: string; domainUsage: string; } interface FlashCardProps { card: FlashCard; } const FlashCard: React.FC<FlashCardProps> = ({ card }) => { return ( <div className="max-w-3xl mx-auto bg-white shadow-lg rounded-lg p-6 my-6"> {/* Phrase Header */} <h2 className="text-2xl font-bold mb-4">πŸ”€ {card.phrase}</h2> {/* Explanation Section */} <section className="mb-4"> <h3 className="text-xl font-semibold mb-2">πŸ“˜ Explanation</h3> <p className="mb-2"><strong>Definition:</strong> {card.meaning}</p> <p className="mb-2"> <strong>Phrase Breakdown:</strong> <ul className="list-disc list-inside"> {card.breakdown.map((item, index) => ( <li key={index}>{item}</li> ))} </ul> </p> <p className="mb-2"><strong>Meaning (in simple English):</strong> {card.simpleMeaning}</p> <p className="mb-2"><strong>Usage Context:</strong> {card.usageContext}</p> </section> {/* Examples Section */} {card.examples.length > 0 && ( <section className="mb-4"> <h3 className="text-xl font-semibold mb-2">🧠 Examples</h3> <table className="table-auto border-collapse w-full"> <thead> <tr> <th className="border p-2 text-left">English Sentence</th> <th className="border p-2 text-left">Simple Meaning</th> </tr> </thead> <tbody> {card.examples.map((ex, index) => ( <tr key={index}> <td className="border p-2">{ex.sentence}</td> <td className="border p-2">{ex.explanation}</td> </tr> ))} </tbody> </table> </section> )} {/* Similar Phrases */} {card.similarPhrases.length > 0 && ( <section className="mb-4"> <h3 className="text-xl font-semibold mb-2">πŸ” Similar Phrases</h3> <ul className="list-disc list-inside"> {card.similarPhrases.map((phrase, index) => ( <li key={index}>{phrase}</li> ))} </ul> </section> )} {/* Memory Tip */} {card.tip && ( <section className="mb-4"> <h3 className="text-xl font-semibold mb-2">πŸ“Œ Memory Tip</h3> <p>{card.tip}</p> </section> )} {/* Field / Domain Usage */} {card.domainUsage && ( <section> <h3 className="text-xl font-semibold mb-2">🧩 Field Usage</h3> <p>{card.domainUsage}</p> </section> )} </div> ); }; export default FlashCard; 
Enter fullscreen mode Exit fullscreen mode

2. Create a Next.js Page to Consume the API

Here’s an example of a simple page in the app directory (if you’re using the Next.js App Router) or pages/index.tsx if you’re on the Pages Router.

If using App Router (Next.js 13+ with /app):

Create or update app/page.tsx:

'use client'; import { useState } from 'react'; import FlashCard, { FlashCard as FlashCardType } from '../components/FlashCard'; export default function Home() { const [input, setInput] = useState(''); const [flashCard, setFlashCard] = useState<FlashCardType | null>(null); const [loading, setLoading] = useState(false); const [error, setError] = useState<string>(''); const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); setLoading(true); setError(''); setFlashCard(null); try { const res = await fetch(`${process.env.NEXT_PUBLIC_API_URL}/phrase/explain`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ text: input }), }); if (!res.ok) { throw new Error(`Error: ${res.statusText}`); } const data: FlashCardType = await res.json(); setFlashCard(data); } catch (err: any) { console.error(err); setError(err.message); } finally { setLoading(false); } }; return ( <main className="max-w-4xl mx-auto p-8"> <h1 className="text-4xl font-bold mb-6 text-center">🧠 AI Dictionary Flashcard</h1> <form onSubmit={handleSubmit} className="flex gap-4 mb-8"> <input className="flex-1 border rounded-md p-3" type="text" placeholder="Enter an English phrase..." value={input} onChange={(e) => setInput(e.target.value)} /> <button className="bg-blue-600 text-white px-6 py-3 rounded-md hover:bg-blue-700" type="submit" disabled={loading || !input.trim()} > {loading ? 'Loading...' : 'Generate Flashcard'} </button> </form> {error && <p className="text-red-600">{error}</p>} {flashCard && <FlashCard card={flashCard} />} </main> ); } 
Enter fullscreen mode Exit fullscreen mode

If using Pages Router (create pages/index.tsx):

import { useState } from 'react'; import FlashCard, { FlashCard as FlashCardType } from '../components/FlashCard'; export default function Home() { const [input, setInput] = useState(''); const [flashCard, setFlashCard] = useState<FlashCardType | null>(null); const [loading, setLoading] = useState(false); const [error, setError] = useState<string>(''); const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); setLoading(true); setError(''); setFlashCard(null); try { const res = await fetch(`${process.env.NEXT_PUBLIC_API_URL}/phrase/explain`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ text: input }), }); if (!res.ok) { throw new Error(`Error: ${res.statusText}`); } const data: FlashCardType = await res.json(); setFlashCard(data); } catch (err: any) { console.error(err); setError(err.message); } finally { setLoading(false); } }; return ( <div className="max-w-4xl mx-auto p-8"> <h1 className="text-4xl font-bold mb-6 text-center">🧠 AI Dictionary Flashcard</h1> <form onSubmit={handleSubmit} className="flex gap-4 mb-8"> <input className="flex-1 border rounded-md p-3" type="text" placeholder="Enter an English phrase..." value={input} onChange={(e) => setInput(e.target.value)} /> <button className="bg-blue-600 text-white px-6 py-3 rounded-md hover:bg-blue-700" type="submit" disabled={loading || !input.trim()} > {loading ? 'Loading...' : 'Generate Flashcard'} </button> </form> {error && <p className="text-red-600">{error}</p>} {flashCard && <FlashCard card={flashCard} />} </div> ); } 
Enter fullscreen mode Exit fullscreen mode

3. Environment Variables

Ensure you have a .env.local file in your Next.js project with:

NEXT_PUBLIC_API_URL=http://localhost:3000 
Enter fullscreen mode Exit fullscreen mode

Replace http://localhost:3000 with your backend URL as needed.


βœ… 4. Enable CORS in NestJS (for local testing)

In main.ts (NestJS):

app.enableCors({ origin: 'http://localhost:3000', }); 
Enter fullscreen mode Exit fullscreen mode

βœ… 5. Run Both Apps

# Backend npm run start:dev # (port 3000) # Frontend npm run dev # (port 3000 default β†’ change one to 3001) 
Enter fullscreen mode Exit fullscreen mode

Top comments (0)