MemoryLane: Building A Dynamic Time Capsule App with Pinata FILE API
DrPrime01
Posted on October 10, 2024
This is a submission for the The Pinata Challenge
What I Built
I built MemoryLane, a digital time capsule application that allows users to preserve moments and thoughts as files and rediscover them in the future. The project combines the nostalgia of traditional time capsules with modern cloud storage technology, leveraging Pinata's File API for secure and efficient file management.
Key features of MemoryLane include:
- Digital preservation of memories
- Future revelations based on user-set dates
- Flexible time-frames for capsule opening
- Multi-media experiences (supporting various file types)
- Personal and collaborative options
- Security and privacy
- Cloud-based reliability
The application was built using:
- NextJS (TypeScript variant)
- Pinata SDK for file uploads and management
- React-dropzone for handling file inputs
- Axios for API calls
- Date-fns for date formatting
Technical implementation highlights:
- Project setup with NextJS and necessary dependencies
- Integration with Pinata using environment variables for API keys
- Custom components for file upload and time capsule display
- Server-side API route for handling file uploads to Pinata
- Client-side state management for time capsules using React hooks
- Local storage integration for persisting time capsules between sessions
- Deployment to Vercel for hosting the application
The project demonstrates the use of Pinata's features including:
- File uploads using the Pinata SDK
- Creation of signed URLs for secure file access
- Integration with NextJS API routes for server-side file handling
This project showcases how Pinata can be effectively used in a Web2 application, highlighting its versatility beyond Web3 and dApp development.
Demo
Link: MemoryLane
My Code
More Details
In the MemoryLane project, Pinata's features were integral to the core functionality of storing and retrieving time capsule files. Here are detailed examples of how Pinata was used:
- Pinata SDK Integration:
The project uses Pinata SDK for seamless interaction with Pinata's services. This is set up in the
utils/config.ts
file:
import { PinataSDK } from "pinata"
export const pinata = new PinataSDK({
pinataJwt: `${process.env.PINATA_JWT}`,
pinataGateway: `${process.env.NEXT_PUBLIC_PINATA_GATEWAY_URL}`
})
This configuration allows the application to use Pinata's services throughout the server-side code.
- File Upload to Pinata:
In the
api/files/route.ts
file, we handle file uploads using Pinata's SDK:
import { NextResponse, NextRequest } from "next/server";
import { pinata } from "@/utils/config";
export async function POST(req: NextRequest) {
try {
const data = await req.formData();
const file: File | null = data.get("file") as unknown as File;
const uploadData = await pinata.upload.file(file);
const url = await pinata.gateways.createSignedURL({
cid: uploadData.cid,
expires: 360000,
});
return NextResponse.json({ url }, { status: 200 });
} catch (e) {
console.error(e);
return NextResponse.json(
{ error: "Internal Server Error" },
{ status: 500 }
);
}
}
This code snippet demonstrates how we use Pinata to upload files directly from the user's input.
- Creating Signed URLs: After uploading a file, we generate a signed URL for secure access:
const url = await pinata.gateways.createSignedURL({
cid: uploadData.cid,
expires: 360000,
});
This signed URL ensures that only authorized users can access the uploaded files, enhancing the security of our time capsules.
- Frontend Integration: On the frontend, we use these signed URLs to display images securely:
import Image from "next/image";
import { format } from "date-fns";
import InfoIcon from "@/assets/icons/info-icon";
import LockIcon from "@/assets/icons/lock-icon";
import { TimeCapsuleStateType } from "@/types";
export default function TimeCapsule({
url,
openDate,
created_at,
}: TimeCapsuleStateType) {
return (
<div className="flex flex-col gap-y-2 max-w-[240px]">
<div className="relative">
<Image
src={url}
width={240}
height={240}
alt="time capsule"
className="object-cover aspect-square"
/>
{new Date() < new Date(openDate) && (
<div className="absolute bg-black/85 inset-0 flex items-center justify-center">
<LockIcon />
</div>
)}
</div>
<p className="text-sm font-medium text-gray-700">
To be opened on {format(openDate, "dd/MM/yyyy")}
</p>
<div className="bg-gray-200 flex space-x-1.5 p-2 rounded-xl">
<InfoIcon />
<p className="text-xs text-gray-500">
This time capsule was created on {format(created_at, "dd/MM/yyyy")}
</p>
</div>
</div>
);
}
The url
here is the signed URL returned from Pinata, allowing us to display the time capsule images without exposing the raw file locations.
- Configuring for Pinata's Gateway:
To ensure NextJS can properly handle images from Pinata's gateway, we configured the
next.config.mjs
file:
const nextConfig = {
images: {
remotePatterns: [
{
protocol: "https",
hostname: "your-gateway-url.mypinata.cloud",
},
],
},
};
This configuration allows NextJS to optimize and serve images from Pinata's gateway efficiently.
By leveraging these features of Pinata, MemoryLane achieves:
- Secure file storage: Files are stored on Pinata's decentralized network, ensuring durability and availability.
- Controlled access: Signed URLs provide a secure way to access files, perfect for the time-release nature of digital time capsules.
- Efficient retrieval: Pinata's gateway ensures fast access to files when it's time to "open" a time capsule.
See here for the full article, explaining the implementation from start to finish.
Cover image by ChatGPT
Posted on October 10, 2024
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.
Related
October 12, 2024