Skip to content

Commit

Permalink
fetch file details and render ui or show 404 page if file expired
Browse files Browse the repository at this point in the history
  • Loading branch information
rajdeep-ghosh committed Jun 7, 2024
1 parent 8f49ccf commit 9201023
Show file tree
Hide file tree
Showing 7 changed files with 109 additions and 38 deletions.
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,14 @@
"@radix-ui/react-slot": "^1.0.2",
"@radix-ui/react-toast": "^1.1.5",
"lucide-react": "^0.378.0",
"mime-types": "^2.1.35",
"mongoose": "^8.4.0",
"next": "^14.1.2",
"react": "^18",
"react-dom": "^18"
},
"devDependencies": {
"@types/mime-types": "^2.1.4",
"@types/node": "^20",
"@types/react": "^18",
"@types/react-dom": "^18",
Expand Down
31 changes: 31 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 5 additions & 6 deletions src/app/api/drop/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,10 @@ import { dbConnect } from '@/lib/db';
import FileModel from '@/lib/models/file';
import { getObject } from '@/lib/s3';

export async function GET(req: NextRequest) {
const { searchParams } = new URL(req.url);
const id = searchParams.get('id');
export async function POST(req: NextRequest) {
const body = (await req.json()) as { id: string };

if (!id) {
if (!body.id) {
return NextResponse.json(
{ error: 'Missing request body parameters' },
{ status: 400 }
Expand All @@ -17,9 +16,9 @@ export async function GET(req: NextRequest) {
try {
await dbConnect();

const file = await FileModel.findById(id);
const file = await FileModel.findById(body.id);

if (!file || new Date().getDate() - file.toJSON().updatedAt.getDate() > 5) {
if (!file || file.toJSON().expires.getTime() - Date.now() <= 0) {
return NextResponse.json({ error: 'File not found' }, { status: 404 });
}

Expand Down
45 changes: 35 additions & 10 deletions src/app/s/[id]/page.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
import { notFound } from 'next/navigation';
import { extension as mimeExtention } from 'mime-types';
import Link from 'next/link';
import { Download } from 'lucide-react';
import { formatBytes } from '@/lib/utils';
import {
Card,
CardContent,
Expand All @@ -8,14 +12,33 @@ import {
CardTitle
} from '@/components/ui/card';
import { Button } from '@/components/ui/button';
import type { DropAPIRespData } from '@/types';

export const dynamic = 'force-dynamic';

type DetailsPageProps = {
params: {
id: string;
};
};

export default async function DetailsPage({ params }: DetailsPageProps) {
const resp = await fetch(`${process.env.NEXT_PUBLIC_URL}/api/drop`, {
method: 'POST',
body: JSON.stringify({
id: params.id
})
});
if (!resp.ok) return notFound();

const { success: data } = (await resp.json()) as DropAPIRespData;

export default function DetailsPage() {
return (
<div className='mx-auto grid max-w-lg gap-8 px-4 sm:px-6 lg:px-8'>
<h1 className='text-center font-poppins text-2xl font-bold tracking-tight text-white sm:text-3xl'>
File shared with you
</h1>
<Card className=''>
<Card>
<CardHeader>
<CardTitle>File Details</CardTitle>
<CardDescription>
Expand All @@ -26,26 +49,28 @@ export default function DetailsPage() {
<div className='grid gap-4'>
<div className='flex justify-between space-x-1 truncate'>
<span className='font-medium'>Name:</span>
<span>Document.pdf</span>
<span>{data.name}</span>
</div>
<div className='flex justify-between'>
<span className='font-medium'>Type:</span>
<span>PDF</span>
<span className='uppercase'>{mimeExtention(data.type)}</span>
</div>
<div className='flex justify-between'>
<span className='font-medium'>Size:</span>
<span>1.2 MB</span>
<span>{formatBytes(data.size)}</span>
</div>
<div className='flex justify-between'>
<span className='font-medium'>Expires in:</span>
<span>12 hr</span>
<span className='font-medium'>Expires:</span>
<span>{new Date(data.expires).toLocaleString()}</span>
</div>
</div>
</CardContent>
<CardFooter>
<Button className='w-full'>
<Download className='mr-2 size-4' />
Download File
<Button className='w-full' asChild>
<Link href={data.url} target='_blank' download>
<Download className='mr-2 size-4' />
Download File
</Link>
</Button>
</CardFooter>
</Card>
Expand Down
45 changes: 25 additions & 20 deletions src/lib/models/file.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,30 @@
import mongoose from 'mongoose';

const fileSchema = new mongoose.Schema(
{
name: {
type: String,
required: true
},
size: {
type: Number,
required: true
},
type: {
type: String,
required: true
},
key: {
type: String,
required: true
}
const fileSchema = new mongoose.Schema({
name: {
type: String,
required: true
},
{ timestamps: true }
);
size: {
type: Number,
required: true
},
type: {
type: String,
required: true
},
key: {
type: String,
required: true
},
expires: {
type: Date,
default: new Date(new Date().setDate(new Date().getDate() + 1)) // +24 hrs
},
created_at: {
type: Date,
default: new Date()
}
});

export default mongoose.model('File', fileSchema);
7 changes: 7 additions & 0 deletions src/lib/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,10 @@ import { twMerge } from 'tailwind-merge';
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs));
}

export function formatBytes(size: number) {
const i = size == 0 ? 0 : Math.floor(Math.log(size) / Math.log(1024));
return (
+(size / Math.pow(1024, i)).toFixed(2) * 1 + ' ' + ['B', 'kB', 'MB'][i]
);
}
6 changes: 4 additions & 2 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,11 @@ export type UploadAPIRespData = {
size: number;
type: string;
key: string;
expires: Date;
url: string;
createdAt: Date;
updatedAt: Date;
created_at: Date;
};
error: string;
};

export type DropAPIRespData = Pick<UploadAPIRespData, 'success'>;

0 comments on commit 9201023

Please sign in to comment.