Skip to content

Commit 71d5262

Browse files
committed
fix: user diff
1 parent 85e72e4 commit 71d5262

10 files changed

Lines changed: 279 additions & 55 deletions

File tree

backend/config/tiers.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ export const TIERS = {
1010
},
1111
[TIER.FREE]: {
1212
maxSize: 200 * 1024 * 1024,
13-
expiryHours: 24,
13+
expiryHours: 168, // 7 days
1414
password: false,
1515
},
1616
[TIER.PRO]: {

backend/routes/handleFile.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,19 @@ router.post("/upload-file", async (req, res) => {
4141
const tierConfig = TIERS[tierKey];
4242

4343
if (size > tierConfig.maxSize) {
44+
const maxSizeMB = Math.round(tierConfig.maxSize / (1024 * 1024));
45+
const fileSizeMB = Math.round(size / (1024 * 1024));
46+
4447
return res.status(400).json({
45-
error: `File too large. Max size for ${tier} tier: ${tierConfig.maxSize / (1024 * 1024)}MB`
48+
error: "FILE_TOO_LARGE",
49+
message: `File too large. Your file is ${fileSizeMB}MB but the ${tier} tier limit is ${maxSizeMB}MB.`,
50+
details: {
51+
fileSize: size,
52+
maxSize: tierConfig.maxSize,
53+
tier: tier,
54+
fileSizeMB: fileSizeMB,
55+
maxSizeMB: maxSizeMB
56+
}
4657
})
4758
}
4859

frontend/app/api/auth/[...nextauth]/route.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,10 +66,16 @@ const handler = NextAuth({
6666
const userData = await response.json();
6767
session.user.id = userData.id;
6868
session.user.tier = userData.tier;
69+
} else {
70+
console.warn('Failed to fetch fresh user data, using cached data');
71+
session.user.id = token.id;
72+
session.user.tier = token.tier;
6973
}
7074
}
7175
} catch (error) {
7276
console.error('Error fetching user session:', error);
77+
session.user.id = token.id;
78+
session.user.tier = token.tier;
7379
}
7480

7581
return session;

frontend/app/page.tsx

Lines changed: 56 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,13 @@ import { useState, useEffect } from "react";
44
import { useRouter } from "next/navigation";
55
import { useSession } from "next-auth/react";
66
import UploadSuccessAlert from "@/components/UploadSuccessAlert";
7+
import FileSizeErrorAlert from "@/components/FileSizeErrorAlert";
78
import FileUploadCard from "@/components/FileUploadCard";
89
import WelcomeCard from "@/components/WelcomeCard";
910
import TierInfoSection from "@/components/TierInfoSection";
1011
import Header from "@/components/Header";
1112
import Footer from "@/components/Footer";
12-
import { uploadFile } from "@/lib/api";
13+
import { uploadFile, validateFileSize, calculateExpiryTime } from "@/lib/api";
1314

1415
export default function Home() {
1516
const router = useRouter();
@@ -21,6 +22,7 @@ export default function Home() {
2122
const [fileId, setFileId] = useState<string | null>(null);
2223
const [fileSize, setFileSize] = useState<string>("");
2324
const [uploadSuccess, setUploadSuccess] = useState<boolean>(false);
25+
const [fileSizeError, setFileSizeError] = useState<string | null>(null);
2426

2527
// Auto-close success alert after 3 seconds
2628
useEffect(() => {
@@ -38,12 +40,42 @@ export default function Home() {
3840
setIsSuccess(false);
3941
setUploadSuccess(false);
4042
setProgress(0);
41-
setFileSize((selectedFile.size / 1024).toFixed(2) + " KB");
43+
setFileSizeError(null);
44+
45+
// Convert to appropriate unit
46+
const sizeInMB = selectedFile.size / (1024 * 1024);
47+
if (sizeInMB >= 1) {
48+
setFileSize(sizeInMB.toFixed(2) + " MB");
49+
} else {
50+
setFileSize((selectedFile.size / 1024).toFixed(2) + " KB");
51+
}
52+
};
53+
54+
const scrollToPricing = () => {
55+
const pricingSection = document.getElementById('pricing');
56+
if (pricingSection) {
57+
pricingSection.scrollIntoView({
58+
behavior: 'smooth',
59+
block: 'start'
60+
});
61+
}
4262
};
4363

4464
const handleUpload = async () => {
4565
if (!file) return;
4666

67+
// Clear any previous errors
68+
setFileSizeError(null);
69+
70+
// Client-side validation first
71+
const currentTier = session?.user?.tier?.toLowerCase() || "anonymous";
72+
const validation = validateFileSize(file, currentTier);
73+
74+
if (!validation.isValid) {
75+
setFileSizeError(validation.error || "File size validation failed");
76+
return;
77+
}
78+
4779
setIsUploading(true);
4880
setProgress(0);
4981
setIsSuccess(false);
@@ -53,7 +85,7 @@ export default function Home() {
5385
// 1. Request presigned URL from backend using the new API utility
5486
const { url, key, fileId, tier } = await uploadFile(
5587
file,
56-
session?.user?.tier?.toLowerCase() || "anonymous",
88+
currentTier,
5789
""
5890
);
5991

@@ -87,7 +119,7 @@ export default function Home() {
87119
size: file.size,
88120
tier: tier || "anonymous",
89121
hasPassword: false,
90-
expiresAt: new Date(Date.now() + 24 * 60 * 60 * 1000).toISOString(),
122+
expiresAt: calculateExpiryTime(tier || "anonymous"),
91123
downloadCount: 0
92124
};
93125

@@ -117,9 +149,17 @@ export default function Home() {
117149
xhr.setRequestHeader("Content-Type", file.type);
118150
xhr.send(file);
119151
});
120-
} catch (err) {
152+
} catch (err: any) {
121153
console.error("Upload failed", err);
122154
setIsUploading(false);
155+
156+
// Handle file size errors specifically
157+
if (err.error === "FILE_TOO_LARGE" || err.message?.includes("File too large")) {
158+
setFileSizeError(err.message || "File is too large for your current tier");
159+
} else {
160+
// Handle other errors
161+
setFileSizeError(err.message || "Upload failed. Please try again.");
162+
}
123163
} finally {
124164
setIsUploading(false);
125165
}
@@ -144,6 +184,7 @@ export default function Home() {
144184
isUploading={isUploading}
145185
progress={progress}
146186
uploadSuccess={uploadSuccess}
187+
tier={session?.user?.tier?.toLowerCase() || "anonymous"}
147188
/>
148189
</div>
149190

@@ -163,6 +204,16 @@ export default function Home() {
163204
{isSuccess && (
164205
<UploadSuccessAlert onClose={() => setIsSuccess(false)} />
165206
)}
207+
208+
{/* File Size Error Alert */}
209+
{fileSizeError && (
210+
<FileSizeErrorAlert
211+
error={fileSizeError}
212+
onClose={() => setFileSizeError(null)}
213+
onUpgrade={scrollToPricing}
214+
/>
215+
)}
216+
166217
<Footer />
167218
</div>
168219
);

frontend/app/results/[id]/page.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import Header from "@/components/Header";
2121
import Footer from "@/components/Footer";
2222
import QRCode from "qrcode";
2323
import Image from "next/image";
24+
import { calculateExpiryTime } from "@/lib/api";
2425

2526
interface FileData {
2627
id: string;
@@ -92,7 +93,7 @@ export default function ResultsPage() {
9293
size: 1024000, // 1MB default
9394
tier: "anonymous",
9495
hasPassword: false,
95-
expiresAt: new Date(Date.now() + 24 * 60 * 60 * 1000).toISOString(),
96+
expiresAt: calculateExpiryTime("anonymous"),
9697
downloadCount: 0
9798
});
9899
}
@@ -106,7 +107,7 @@ export default function ResultsPage() {
106107
size: 1024000,
107108
tier: "anonymous",
108109
hasPassword: false,
109-
expiresAt: new Date(Date.now() + 24 * 60 * 60 * 1000).toISOString(),
110+
expiresAt: calculateExpiryTime("anonymous"),
110111
downloadCount: 0
111112
});
112113
} finally {
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
"use client";
2+
3+
import { Alert, AlertDescription } from "@/components/ui/alert";
4+
import { Button } from "@/components/ui/button";
5+
import { X, AlertTriangle, Crown } from "lucide-react";
6+
7+
interface FileSizeErrorAlertProps {
8+
error: string;
9+
onClose: () => void;
10+
onUpgrade?: () => void;
11+
}
12+
13+
export default function FileSizeErrorAlert({ error, onClose, onUpgrade }: FileSizeErrorAlertProps) {
14+
return (
15+
<div className="fixed inset-0 bg-black/50 flex items-center justify-center z-50 p-4">
16+
<div className="bg-white rounded-lg shadow-xl max-w-md w-full">
17+
<div className="p-6">
18+
<div className="flex items-start gap-3">
19+
<div className="flex-shrink-0">
20+
<AlertTriangle className="w-6 h-6 text-red-500" />
21+
</div>
22+
<div className="flex-1">
23+
<h3 className="text-lg font-semibold text-gray-900 mb-2">
24+
File Too Large
25+
</h3>
26+
<p className="text-gray-600 mb-4">
27+
{error}
28+
</p>
29+
<div className="flex gap-3">
30+
{onUpgrade && (
31+
<Button
32+
onClick={onUpgrade}
33+
className="flex items-center gap-2 bg-purple-600 hover:bg-purple-700"
34+
>
35+
<Crown className="w-4 h-4" />
36+
Upgrade to Pro
37+
</Button>
38+
)}
39+
<Button
40+
onClick={onClose}
41+
variant="outline"
42+
className="flex items-center gap-2"
43+
>
44+
<X className="w-4 h-4" />
45+
Close
46+
</Button>
47+
</div>
48+
</div>
49+
</div>
50+
</div>
51+
</div>
52+
</div>
53+
);
54+
}
55+

frontend/components/FileUploadCard.tsx

Lines changed: 28 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/com
66
import { Progress } from "@/components/ui/progress";
77
import { Upload, File, Loader2, CheckCircle2 } from "lucide-react";
88
import { cn } from "@/lib/utils";
9+
import { getTierDisplayInfo } from "@/lib/api";
910

1011
interface FileUploadCardProps {
1112
onFileSelect: (file: File) => void;
@@ -14,6 +15,7 @@ interface FileUploadCardProps {
1415
isUploading: boolean;
1516
progress: number;
1617
uploadSuccess: boolean;
18+
tier?: string;
1719
}
1820

1921
export default function FileUploadCard({
@@ -22,7 +24,8 @@ export default function FileUploadCard({
2224
file,
2325
isUploading,
2426
progress,
25-
uploadSuccess
27+
uploadSuccess,
28+
tier = "anonymous"
2629
}: FileUploadCardProps) {
2730
const [isDragOver, setIsDragOver] = useState(false);
2831
const fileInputRef = useRef<HTMLInputElement>(null);
@@ -37,7 +40,7 @@ export default function FileUploadCard({
3740
const handleDrop = (e: React.DragEvent<HTMLDivElement>) => {
3841
e.preventDefault();
3942
setIsDragOver(false);
40-
43+
4144
const droppedFile = e.dataTransfer.files[0];
4245
if (droppedFile) {
4346
onFileSelect(droppedFile);
@@ -61,6 +64,8 @@ export default function FileUploadCard({
6164
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
6265
};
6366

67+
const tierInfo = getTierDisplayInfo(tier);
68+
6469
return (
6570
<Card className="w-full max-w-md">
6671
<CardHeader>
@@ -69,10 +74,10 @@ export default function FileUploadCard({
6974
Upload File
7075
</CardTitle>
7176
<CardDescription>
72-
Choose a file to share securely with our anonymous tier
77+
Choose a file to share securely with your {tierInfo.name} tier
7378
</CardDescription>
7479
</CardHeader>
75-
80+
7681
<CardContent className="space-y-4">
7782
{/* File Drop Zone */}
7883
<div
@@ -82,8 +87,8 @@ export default function FileUploadCard({
8287
onDragLeave={handleDragLeave}
8388
className={cn(
8489
"relative border-2 border-dashed rounded-lg p-8 text-center transition-all duration-200 cursor-pointer",
85-
isDragOver
86-
? "border-blue-500 bg-blue-50"
90+
isDragOver
91+
? "border-blue-500 bg-blue-50"
8792
: "border-gray-300 hover:border-gray-400 hover:bg-gray-50",
8893
isUploading && "opacity-50 cursor-not-allowed",
8994
uploadSuccess && "border-green-500 bg-green-50"
@@ -96,7 +101,7 @@ export default function FileUploadCard({
96101
className="hidden"
97102
disabled={isUploading}
98103
/>
99-
104+
100105
<div className="flex flex-col items-center gap-3">
101106
{uploadSuccess ? (
102107
<CheckCircle2 className="w-12 h-12 text-green-500" />
@@ -105,21 +110,21 @@ export default function FileUploadCard({
105110
) : (
106111
<Upload className="w-12 h-12 text-gray-400" />
107112
)}
108-
113+
109114
<div className="space-y-1">
110115
<p className="text-sm font-medium text-gray-900">
111-
{uploadSuccess
112-
? "Upload Complete!"
113-
: isUploading
114-
? "Uploading..."
115-
: isDragOver
116-
? "Drop file here"
116+
{uploadSuccess
117+
? "Upload Complete!"
118+
: isUploading
119+
? "Uploading..."
120+
: isDragOver
121+
? "Drop file here"
117122
: "Click to upload or drag & drop"
118123
}
119124
</p>
120125
<p className="text-xs text-gray-500">
121-
{uploadSuccess
122-
? "Your file is ready to share"
126+
{uploadSuccess
127+
? "Your file is ready to share"
123128
: "Supports all file types"
124129
}
125130
</p>
@@ -182,20 +187,20 @@ export default function FileUploadCard({
182187
<div className="text-center space-y-2 pt-2 border-t">
183188
<div className="flex justify-center gap-4 text-xs text-gray-500">
184189
<span className="flex items-center gap-1">
185-
<div className="w-2 h-2 bg-gray-400 rounded-full"></div>
186-
Anonymous
190+
<div className={`w-2 h-2 ${tierInfo.color} rounded-full`}></div>
191+
{tierInfo.name}
187192
</span>
188193
<span className="flex items-center gap-1">
189-
<div className="w-2 h-2 bg-gray-400 rounded-full"></div>
190-
24h Expiry
194+
<div className={`w-2 h-2 ${tierInfo.color} rounded-full`}></div>
195+
{tierInfo.expiry} Expiry
191196
</span>
192197
<span className="flex items-center gap-1">
193-
<div className="w-2 h-2 bg-gray-400 rounded-full"></div>
194-
Up to 10MB
198+
<div className={`w-2 h-2 ${tierInfo.color} rounded-full`}></div>
199+
Up to {tierInfo.maxSize}
195200
</span>
196201
</div>
197202
<p className="text-xs text-gray-400">
198-
No registration required • Secure & private
203+
{tierInfo.description}
199204
</p>
200205
</div>
201206
</CardContent>

0 commit comments

Comments
 (0)