Spaces:
Sleeping
Sleeping
eeshaAI commited on
Commit ·
aa1f0fd
1
Parent(s): 4d91720
fix: search shows products immediately (AI loads in background) + more dramatic page transitions
Browse files- src/app/search/page.tsx +21 -18
- src/app/template.tsx +6 -9
src/app/search/page.tsx
CHANGED
|
@@ -35,19 +35,10 @@ function SearchContent() {
|
|
| 35 |
setAllProducts([]);
|
| 36 |
setVideos([]);
|
| 37 |
|
| 38 |
-
//
|
| 39 |
-
const [searchResp, vidResp
|
| 40 |
api.products.search(q, null),
|
| 41 |
api.videos.feed(50).catch(() => ({ success: false, videos: [] })),
|
| 42 |
-
fetch('/api/ai-chat', {
|
| 43 |
-
method: 'POST',
|
| 44 |
-
headers: { 'Content-Type': 'application/json' },
|
| 45 |
-
body: JSON.stringify({
|
| 46 |
-
message: `A user searched for "${q}" on Cellex (a Nigerian e-commerce marketplace). Provide a helpful, comprehensive answer about what's available. Mention types of products, price ranges, and shopping tips. Be friendly and informative (2-3 paragraphs).`,
|
| 47 |
-
context: 'Search overview',
|
| 48 |
-
history: [],
|
| 49 |
-
}),
|
| 50 |
-
}),
|
| 51 |
]);
|
| 52 |
|
| 53 |
const products = searchResp.success
|
|
@@ -55,6 +46,7 @@ function SearchContent() {
|
|
| 55 |
: [];
|
| 56 |
setAllProducts(products);
|
| 57 |
setAiProducts(products.slice(0, 4));
|
|
|
|
| 58 |
|
| 59 |
// Filter videos
|
| 60 |
if (vidResp.success) {
|
|
@@ -67,15 +59,26 @@ function SearchContent() {
|
|
| 67 |
setVideos(filtered);
|
| 68 |
}
|
| 69 |
|
| 70 |
-
// AI response
|
| 71 |
-
|
| 72 |
-
const
|
| 73 |
-
|
| 74 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 75 |
setAiAnswer(`Here's what I found for "${q}": ${products.length} products available on Cellex.`);
|
| 76 |
}
|
| 77 |
-
|
| 78 |
-
setLoading(false);
|
| 79 |
}, []);
|
| 80 |
|
| 81 |
useEffect(() => {
|
|
|
|
| 35 |
setAllProducts([]);
|
| 36 |
setVideos([]);
|
| 37 |
|
| 38 |
+
// Step 1: Fetch products + videos FIRST (fast, shows results immediately)
|
| 39 |
+
const [searchResp, vidResp] = await Promise.all([
|
| 40 |
api.products.search(q, null),
|
| 41 |
api.videos.feed(50).catch(() => ({ success: false, videos: [] })),
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 42 |
]);
|
| 43 |
|
| 44 |
const products = searchResp.success
|
|
|
|
| 46 |
: [];
|
| 47 |
setAllProducts(products);
|
| 48 |
setAiProducts(products.slice(0, 4));
|
| 49 |
+
setLoading(false); // Stop loading — products are visible now
|
| 50 |
|
| 51 |
// Filter videos
|
| 52 |
if (vidResp.success) {
|
|
|
|
| 59 |
setVideos(filtered);
|
| 60 |
}
|
| 61 |
|
| 62 |
+
// Step 2: Fetch AI response IN THE BACKGROUND (don't block product display)
|
| 63 |
+
try {
|
| 64 |
+
const aiResp = await fetch('/api/ai-chat', {
|
| 65 |
+
method: 'POST',
|
| 66 |
+
headers: { 'Content-Type': 'application/json' },
|
| 67 |
+
body: JSON.stringify({
|
| 68 |
+
message: `A user searched for "${q}" on Cellex (a Nigerian e-commerce marketplace). Provide a helpful, comprehensive answer about what's available. Mention types of products, price ranges, and shopping tips. Be friendly and informative (2-3 paragraphs).`,
|
| 69 |
+
context: 'Search overview',
|
| 70 |
+
history: [],
|
| 71 |
+
}),
|
| 72 |
+
});
|
| 73 |
+
if (aiResp.ok) {
|
| 74 |
+
const data = await aiResp.json();
|
| 75 |
+
setAiAnswer(data.reply || data.message || data.content || `Here's what I found for "${q}": ${products.length} products available on Cellex.`);
|
| 76 |
+
} else {
|
| 77 |
+
setAiAnswer(`Here's what I found for "${q}": ${products.length} products available on Cellex.`);
|
| 78 |
+
}
|
| 79 |
+
} catch {
|
| 80 |
setAiAnswer(`Here's what I found for "${q}": ${products.length} products available on Cellex.`);
|
| 81 |
}
|
|
|
|
|
|
|
| 82 |
}, []);
|
| 83 |
|
| 84 |
useEffect(() => {
|
src/app/template.tsx
CHANGED
|
@@ -5,11 +5,8 @@ import { motion } from 'framer-motion';
|
|
| 5 |
|
| 6 |
/**
|
| 7 |
* Template — cinematic page transitions using framer-motion.
|
| 8 |
-
*
|
| 9 |
-
*
|
| 10 |
-
* - Enters: slides in from right (12px) + fades in + slides up (8px)
|
| 11 |
-
* - Uses spring physics for a natural, premium feel
|
| 12 |
-
* - Re-triggers on every pathname change
|
| 13 |
*/
|
| 14 |
export default function Template({ children }: { children: React.ReactNode }) {
|
| 15 |
const pathname = usePathname();
|
|
@@ -17,10 +14,10 @@ export default function Template({ children }: { children: React.ReactNode }) {
|
|
| 17 |
return (
|
| 18 |
<motion.div
|
| 19 |
key={pathname}
|
| 20 |
-
initial={{ opacity: 0, x:
|
| 21 |
-
animate={{ opacity: 1, x: 0,
|
| 22 |
-
|
| 23 |
-
|
| 24 |
>
|
| 25 |
{children}
|
| 26 |
</motion.div>
|
|
|
|
| 5 |
|
| 6 |
/**
|
| 7 |
* Template — cinematic page transitions using framer-motion.
|
| 8 |
+
* More dramatic: slides in from right + scales up slightly + fades in.
|
| 9 |
+
* Re-triggers on every pathname change.
|
|
|
|
|
|
|
|
|
|
| 10 |
*/
|
| 11 |
export default function Template({ children }: { children: React.ReactNode }) {
|
| 12 |
const pathname = usePathname();
|
|
|
|
| 14 |
return (
|
| 15 |
<motion.div
|
| 16 |
key={pathname}
|
| 17 |
+
initial={{ opacity: 0, x: 30, scale: 0.98 }}
|
| 18 |
+
animate={{ opacity: 1, x: 0, scale: 1 }}
|
| 19 |
+
transition={{ duration: 0.4, ease: [0.22, 1, 0.36, 1] }}
|
| 20 |
+
style={{ willChange: 'transform, opacity' }}
|
| 21 |
>
|
| 22 |
{children}
|
| 23 |
</motion.div>
|