diff --git a/apps/hackathon/src/app/onboarding/user/page.tsx b/apps/hackathon/src/app/onboarding/user/page.tsx
index a21b308..9d4c641 100644
--- a/apps/hackathon/src/app/onboarding/user/page.tsx
+++ b/apps/hackathon/src/app/onboarding/user/page.tsx
@@ -60,6 +60,20 @@ const UserOnboardingPage: FC = (): ReactElement => {
const handleAvatarChange = (e: React.ChangeEvent) => {
const file = e.target.files?.[0];
if (file) {
+ // Validate file size (max 2MB)
+ if (file.size > 2 * 1024 * 1024) {
+ toast.error('The file is too large. Maximum size is 2MB.');
+ e.target.value = '';
+ return;
+ }
+
+ // Validate file type
+ if (!file.type.startsWith('image/')) {
+ toast.error('The file must be an image');
+ e.target.value = '';
+ return;
+ }
+
setAvatarFile(file);
const reader = new FileReader();
reader.onloadend = () => {
@@ -150,7 +164,7 @@ const UserOnboardingPage: FC = (): ReactElement => {
/>
- Optional, but highly recommended
+ Optional, but highly recommended. Max 2MB
diff --git a/apps/hackathon/src/app/profile/page.tsx b/apps/hackathon/src/app/profile/page.tsx
index 04fc242..f8f107f 100644
--- a/apps/hackathon/src/app/profile/page.tsx
+++ b/apps/hackathon/src/app/profile/page.tsx
@@ -84,15 +84,17 @@ const ProfilePage: FC = ({
const handleAvatarChange = (e: React.ChangeEvent) => {
const file = e.target.files?.[0];
if (file) {
- // Validate file size (max 5MB)
- if (file.size > 5 * 1024 * 1024) {
- toast.error('The file is too large. Maximum 5MB');
+ // Validate file size (max 2MB)
+ if (file.size > 2 * 1024 * 1024) {
+ toast.error('The file is too large. Maximum size is 2MB.');
+ e.target.value = '';
return;
}
// Validate file type
if (!file.type.startsWith('image/')) {
toast.error('The file must be an image');
+ e.target.value = '';
return;
}
@@ -235,7 +237,7 @@ const ProfilePage: FC = ({
Click the camera icon to change your photo
- Format: JPG, PNG. Max 5MB
+ Format: JPG, PNG. Max 2MB
diff --git a/apps/hackathon/src/app/teams/[teamId]/edit/page.tsx b/apps/hackathon/src/app/teams/[teamId]/edit/page.tsx
index a6170f0..6b7441b 100644
--- a/apps/hackathon/src/app/teams/[teamId]/edit/page.tsx
+++ b/apps/hackathon/src/app/teams/[teamId]/edit/page.tsx
@@ -16,6 +16,9 @@ import { zodResolver } from '@hookform/resolvers/zod';
import { CitySelect } from '../../../../components/city-select';
import { Icon } from '@iconify/react';
+import { toast } from 'sonner';
+
+const MAX_FILE_SIZE = 2 * 1024 * 1024; // 2MB
const EditTeamPage: FC = (): ReactElement => {
const { teamId } = useParams<{ teamId: string }>();
@@ -85,6 +88,11 @@ const EditTeamPage: FC = (): ReactElement => {
const handleLogoChange = (e: React.ChangeEvent) => {
const file = e.target.files?.[0];
if (file) {
+ if (file.size > MAX_FILE_SIZE) {
+ toast.error('Logo image is too large. Maximum size is 2MB.');
+ e.target.value = '';
+ return;
+ }
setLogoFile(file);
const reader = new FileReader();
reader.onloadend = () => {
@@ -97,6 +105,11 @@ const EditTeamPage: FC = (): ReactElement => {
const handleBannerChange = (e: React.ChangeEvent) => {
const file = e.target.files?.[0];
if (file) {
+ if (file.size > MAX_FILE_SIZE) {
+ toast.error('Banner image is too large. Maximum size is 2MB.');
+ e.target.value = '';
+ return;
+ }
setBannerFile(file);
const reader = new FileReader();
reader.onloadend = () => {
@@ -183,7 +196,7 @@ const EditTeamPage: FC = (): ReactElement => {
Click to upload banner
- 1200x400 recommended
+ 1200x400 recommended. Max 2MB
{
)}
-
-
- {logoPreview && (
-
- )}
+
+
+
+ {logoPreview && (
+
+ )}
+
+
Max 2MB
diff --git a/apps/hackathon/src/app/teams/[teamId]/submit/page.tsx b/apps/hackathon/src/app/teams/[teamId]/submit/page.tsx
index a72227a..72a38f6 100644
--- a/apps/hackathon/src/app/teams/[teamId]/submit/page.tsx
+++ b/apps/hackathon/src/app/teams/[teamId]/submit/page.tsx
@@ -13,8 +13,10 @@ import {
useAuthStore,
} from '@imphnen-frontend-service/service';
import { zodResolver } from '@hookform/resolvers/zod';
+import { toast } from 'sonner';
const MIN_TEAM_MEMBERS = 2; // Minimum members required to submit (including leader)
+const MAX_FILE_SIZE = 2 * 1024 * 1024; // 2MB
const SubmitProjectPage: FC = (): ReactElement => {
const { teamId } = useParams<{ teamId: string }>();
@@ -89,6 +91,14 @@ const SubmitProjectPage: FC = (): ReactElement => {
const files = e.target.files;
if (!files) return;
+ // Validate file sizes
+ const oversizedFiles = Array.from(files).filter(file => file.size > MAX_FILE_SIZE);
+ if (oversizedFiles.length > 0) {
+ toast.error(`${oversizedFiles.length} file(s) are too large. Maximum size is 2MB per file.`);
+ e.target.value = '';
+ return;
+ }
+
try {
const uploadPromises = Array.from(files).map((file) => uploadFile(file));
const results = await Promise.all(uploadPromises);
@@ -96,6 +106,7 @@ const SubmitProjectPage: FC = (): ReactElement => {
setScreenshots([...screenshots, ...urls]);
} catch (error) {
console.error('Failed to upload screenshots:', error);
+ toast.error('Failed to upload screenshots. Please try again.');
}
};
@@ -271,7 +282,7 @@ const SubmitProjectPage: FC = (): ReactElement => {
Click to upload screenshots
- PNG, JPG up to 5MB each
+ PNG, JPG. Max 2MB each
{
const navigate = useNavigate();
const [logoFile, setLogoFile] = useState(null);
@@ -31,6 +34,11 @@ const CreateTeamPage: FC = (): ReactElement => {
const handleLogoChange = (e: React.ChangeEvent) => {
const file = e.target.files?.[0];
if (file) {
+ if (file.size > MAX_FILE_SIZE) {
+ toast.error('Logo image is too large. Maximum size is 2MB.');
+ e.target.value = '';
+ return;
+ }
setLogoFile(file);
const reader = new FileReader();
reader.onloadend = () => {
@@ -43,6 +51,11 @@ const CreateTeamPage: FC = (): ReactElement => {
const handleBannerChange = (e: React.ChangeEvent) => {
const file = e.target.files?.[0];
if (file) {
+ if (file.size > MAX_FILE_SIZE) {
+ toast.error('Banner image is too large. Maximum size is 2MB.');
+ e.target.value = '';
+ return;
+ }
setBannerFile(file);
const reader = new FileReader();
reader.onloadend = () => {
@@ -73,9 +86,20 @@ const CreateTeamPage: FC = (): ReactElement => {
banner: bannerUrl,
});
+ toast.success('Team created successfully!');
navigate(`/teams/${result.data.id}`);
- } catch (error) {
+ } catch (error: any) {
console.error('Failed to create team:', error);
+
+ // Handle specific error messages
+ const message = error?.message || '';
+ if (message.includes('413') || message.includes('length limit') || message.includes('too large')) {
+ toast.error('Image file is too large. Please use smaller images (max 2MB each).');
+ } else if (message.includes('already a member')) {
+ toast.error(message);
+ } else {
+ toast.error(message || 'Failed to create team. Please try again.');
+ }
}
});
@@ -119,7 +143,7 @@ const CreateTeamPage: FC = (): ReactElement => {