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;
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>
);
}
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>
);
}
3. Environment Variables
Ensure you have a .env.local
file in your Next.js project with:
NEXT_PUBLIC_API_URL=http://localhost:3000
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',
});
β 5. Run Both Apps
# Backend
npm run start:dev # (port 3000)
# Frontend
npm run dev # (port 3000 default β change one to 3001)
Top comments (0)