tia/src/app/memories/page.tsx
Mannu fdd2a67f7a Fix hardcoded IDs and data fetching across all pages
- Add signout button to menu (below Settings)
- Fix profile API to fetch user from database session
- Fix profile page to save name to database
- Fix settings page to use familyId from FamilyProvider
- Fix family page to use FamilyProvider
- Fix activity, ai, medical, memories pages to use FamilyProvider
- Remove all hardcoded "default" familyId and childId values

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-11 00:32:31 +05:30

144 lines
No EOL
4.5 KiB
TypeScript

"use client";
import { useState, useEffect, useRef } from "react";
import Link from "next/link";
import { useFamily } from "../FamilyProvider";
interface Memory {
key: string;
url: string;
size: number;
lastModified: string;
}
export default function MemoriesPage() {
const { childId } = useFamily();
const [memories, setMemories] = useState<Memory[]>([]);
const [selected, setSelected] = useState<Memory | null>(null);
const [uploading, setUploading] = useState(false);
const [uploadProgress, setUploadProgress] = useState(0);
const fileRef = useRef<HTMLInputElement>(null);
useEffect(() => {
if (childId) {
fetchMemories();
}
}, [childId]);
const fetchMemories = async () => {
if (!childId) return;
try {
const res = await fetch(`/api/upload?childId=${childId}`);
const data = await res.json();
setMemories(data.items || []);
} catch (err) {
console.error("Failed to fetch memories:", err);
}
};
const handleUpload = async (e: React.ChangeEvent<HTMLInputElement>) => {
const file = e.target.files?.[0];
if (!file) return;
setUploading(true);
setUploadProgress(0);
try {
// Get upload key
const res = await fetch("/api/upload", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ filename: file.name, contentType: file.type, childId }),
});
const data = await res.json();
if (data.error) {
alert("Error: " + data.error);
setUploading(false);
return;
}
const { key, publicUrl } = data;
// Upload through our server (no CORS issue)
const uploadRes = await fetch(`/api/upload?key=${encodeURIComponent(key)}&contentType=${encodeURIComponent(file.type)}`, {
method: "PUT",
body: file,
});
const uploadData = await uploadRes.json();
if (uploadData.success) {
setMemories([{ key, url: publicUrl, size: file.size, lastModified: new Date().toISOString() }, ...memories]);
} else {
alert("Upload failed: " + uploadData.error);
}
} catch (err) {
console.error("Upload failed:", err);
alert("Error: " + err);
}
setUploading(false);
setUploadProgress(0);
if (fileRef.current) fileRef.current.value = "";
};
return (
<div className="min-h-screen bg-gradient-to-br from-rose-50 to-amber-50 dark:from-gray-900 dark:to-gray-800">
<div className="p-4 flex items-center gap-4">
<Link href="/menu" className="p-2"></Link>
<h1 className="text-xl font-bold">Memories 📸</h1>
</div>
<div className="px-4">
{memories.length === 0 ? (
<div className="text-center py-20 text-gray-400">
<div className="text-6xl mb-4">📷</div>
<p>No memories yet</p>
<p className="text-sm">Tap + to add your first photo</p>
</div>
) : (
<div className="grid grid-cols-3 gap-1">
{memories.map((mem) => (
<button
key={mem.key}
onClick={() => setSelected(mem)}
className="aspect-square bg-gray-200 dark:bg-gray-700 rounded-lg overflow-hidden"
>
<img src={mem.url} alt={mem.key} className="w-full h-full object-cover" />
</button>
))}
</div>
)}
</div>
{/* Upload Button */}
<div className="fixed bottom-4 right-4">
<label className="w-14 h-14 bg-rose-400 text-white rounded-full text-2xl shadow-lg flex items-center justify-center cursor-pointer">
{uploading ? (
<span className="text-sm">{uploadProgress}%</span>
) : (
<span>+</span>
)}
<input
ref={fileRef}
type="file"
accept="image/*"
onChange={handleUpload}
className="hidden"
disabled={uploading}
/>
</label>
</div>
{/* Modal */}
{selected && (
<div className="fixed inset-0 bg-black/90 flex items-center justify-center z-50" onClick={() => setSelected(null)}>
<div className="w-full h-full flex items-center justify-center p-4" onClick={e => e.stopPropagation()}>
<img src={selected.url} alt={selected.key} className="max-w-full max-h-full object-contain" />
</div>
<button onClick={() => setSelected(null)} className="absolute top-4 right-4 text-white text-xl p-2"></button>
</div>
)}
</div>
);
}