dev-resources.site
for different kinds of informations.
Wedding Memories: The Collaborative Wedding Album!
Wedding Memories
This is a submission for the The Pinata Challenge
What I Built
Wedding Memories is an app designed to capture, share, and cherish every unforgettable moment from your special day! It allows wedding guests to easily upload photos, creating a collaborative album that captures the essence of the celebration. By using Pinata's Files API, the app provides a seamless experience for secure and efficient media uploads and storage.
Demo
Check out the live version of the app here: Wedding Memories
Screenshots:
- Upload Section - A user-friendly interface for selecting and uploading media files:
- Gallery View - Displays all uploaded memories in a responsive layout:
- Mobile-Optimized Design - Ensures smooth user experience across all devices:
- Download Options - Guests can download their favourite moments to keep memories forever.
My Code
You can explore the full code for this project on GitHub:
More Details
Wedding Memories leverages Pinataโs Files API to build secure and efficient file uploads. Below is a brief breakdown of the integration:
File Uploads: Guests can easily upload images directly from their devices. This is accomplished using the
pinata.upload.file
, which uses JWT-based authentication to ensure secure file handling. Once uploaded, the files are securely stored, and their unique identifiers (CIDs) are generated for retrieval.Local Previews Before Upload: To enhance the guest experience, wedding memories generate local previews of images before uploading them. This feature allows guests to confirm their selections and make adjustments, ensuring only their desired image is submitted.
After successful uploads, the files are rendered using the file API. This guarantees rapid access to the content, providing guests with a seamless experience when viewing shared memories.
- Download Feature: Guests can now download their favourite photos directly from the app, making it easy to save cherished memories to their devices. The app includes an API route that facilitates the secure downloading of files.
API Integration Breakdown:
The building includes several key API routes, each designed to handle specific functionalities:
- File Upload Endpoint
This accepts file uploads and stores them using Pinataโs upload function. It then generates a signed URL for easy access to the uploaded file.
import { NextResponse, NextRequest } from "next/server";
import { pinata } from "../../../../utils/config";
export async function POST(request: NextRequest) {
try {
const data = await request.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: 3600,
});
return NextResponse.json(url, { status: 200 });
} catch (e) {
console.log(e);
return NextResponse.json(
{ error: "Internal Server Error" },
{ status: 500 }
);
}
}
- API Key Generation
(/api/key/route.ts)
:
Creates a temporary API key with permissions to pin files to IPFS.
/* eslint-disable @typescript-eslint/no-unused-vars */
import { NextResponse } from "next/server";
import { pinata } from "../../../../utils/config";
export const dynamic = "force-dynamic";
export async function GET() {
try {
const uuid = crypto.randomUUID();
const keyData = await pinata.keys.create({
keyName: uuid.toString(),
permissions: {
endpoints: {
pinning: {
pinFileToIPFS: true,
},
},
},
maxUses: 1,
})
return NextResponse.json(keyData, { status: 200 });
} catch (error) {
console.log(error);
return NextResponse.json({ text: "Error creating API Key:" }, { status: 500 });
}
}
- List Files
(/api/listfiles/route.ts)
:
Retrieves a list of uploaded files from Pinata, allowing users to view all shared content in the gallery
import { NextResponse } from "next/server";
import { env } from "process";
export const dynamic = "force-dynamic";
export async function GET() {
try {
const options: RequestInit = {
method: 'GET',
headers: {
Authorization: `Bearer ${process.env.NEXT_PUBLIC_PINATA_JWT}`,
},
cache: 'no-cache'
};
const response = await fetch('https://api.pinata.cloud/v3/files', options);
if (!response.ok) {
return NextResponse.json({ text: "Error listing files" }, { status: response.status });
}
const { data } = await response.json();
return NextResponse.json(data, { status: 200 });
} catch (error) {
console.log(error, "Error listing files");
return NextResponse.json({ text: "Error listing files" }, { status: 500 });
}
}
- Image Proxy
(/api/proxy/route.ts)
:
Acts as a proxy for fetching images from external sources, ensuring users can easily access and download their images.
import { NextResponse } from 'next/server';
export async function GET(request: Request) {
const { searchParams } = new URL(request.url);
const imageUrl = searchParams.get('url'); // Get the image URL from the query string
if (!imageUrl) {
return NextResponse.json({ error: 'Image URL is required' }, { status: 400 });
}
try {
const response = await fetch(imageUrl);
if (!response.ok) {
return NextResponse.json({ error: 'Failed to fetch image' }, { status: response.status });
}
const contentType = response.headers.get('content-type') || 'application/octet-stream';
const imageBuffer = await response.arrayBuffer();
return new NextResponse(imageBuffer, {
headers: {
'Content-Type': contentType,
'Content-Disposition': 'attachment; filename="downloaded_image"',
},
});
} catch (error) {
console.error('Error fetching image:', error);
return NextResponse.json({ error: 'Error fetching image' }, { status: 500 });
}
}
- Signed URL Creation
(/api/sign/route.ts)
:
Generates signed URLs for uploaded files.
import { type NextRequest, NextResponse } from "next/server";
import { pinata } from "../../../../utils/config";
export const dynamic = "force-dynamic";
export async function POST(req: NextRequest) {
try {
const data = await req.json();
const mimeType = data.mime_type;
let url;
if (mimeType === 'video/mp4') {
url = await pinata.gateways.createSignedURL({
cid: data.cid,
expires: 7776000,
})
} else {
url = await pinata.gateways.createSignedURL({
cid: data.cid,
expires: 7776000,
}).optimizeImage({
width: 300,
height: 300,
format: "webp",
fit: "contain",
quality: 90,
dpr: 2,
sharpen: 1,
});
}
return NextResponse.json(url, { status: 200 });
} catch (error) {
console.log(error);
return NextResponse.json({ text: "Error creating signed URL:" }, { status: 500 });
}
}
The app is built with:
Pinata: File API
Frontend: React, Next.js, Framer Motion
Styling: Tailwind CSS for responsive, beautiful layouts.
Hosting: Amplify for deployment.
Conclusion
Weddings are joyous occasions filled with love, laughter, and countless memorable moments. Capturing these precious memories is essential, and with the Wedding Memories app, it's now easier than ever!
This application allows every guest to take lovely pictures on the event day and share them seamlessly, ensuring that no moment is missed and everyone has access to the collective memories of the celebration.
The app harnesses the power of Pinata's Files API to provide a secure and efficient way for guests to upload and share their photos and videos, creating a collaborative album that beautifully encapsulates the essence of the day.
For more details on how the app integrates with Pinata and to explore its capabilities, please refer to the Pinata documentation.
Thank you.
Featured ones: