From c160522e29c329c24cacb1251d0af626512a3260 Mon Sep 17 00:00:00 2001 From: Quaternions Date: Mon, 23 Jun 2025 22:53:01 -0700 Subject: [PATCH 1/3] move download button somewhere else --- web/src/app/_components/downloadButton.tsx | 69 ---------------------- web/src/app/maps/[mapId]/page.tsx | 67 +++++++++++++++++++-- 2 files changed, 63 insertions(+), 73 deletions(-) delete mode 100644 web/src/app/_components/downloadButton.tsx diff --git a/web/src/app/_components/downloadButton.tsx b/web/src/app/_components/downloadButton.tsx deleted file mode 100644 index f144aaf..0000000 --- a/web/src/app/_components/downloadButton.tsx +++ /dev/null @@ -1,69 +0,0 @@ -import React, { useState } from 'react'; -import { Button } from '@mui/material'; -import Download from '@mui/icons-material/Download'; - -interface DownloadButtonProps { - assetId: number; - assetName: string; -} - -const DownloadButton: React.FC = ({ assetId, assetName }) => { - const [downloading, setDownloading] = useState(false); - - const handleDownload = async () => { - setDownloading(true); - try { - // Fetch the download URL - const res = await fetch(`/api/maps/${assetId}/location`); - if (!res.ok) throw new Error('Failed to fetch download location'); - - const location = await res.text(); - - // Method 1: Try direct download with proper cleanup - try { - const link = document.createElement('a'); - link.href = location.trim(); // Remove any whitespace - link.download = `${assetName}.rbxm`; - link.target = '_blank'; // Open in new tab as fallback - link.rel = 'noopener noreferrer'; // Security best practice - - // Ensure the link is properly attached before clicking - document.body.appendChild(link); - link.click(); - - // Clean up after a short delay to ensure download starts - setTimeout(() => { - document.body.removeChild(link); - }, 100); - - } catch (domError) { - console.warn('Direct download failed, trying fallback:', domError); - // Method 2: Fallback - open in new window - window.open(location.trim(), '_blank'); - } - - } catch (err) { - console.error('Download error:', err); - // Optional: Show user-friendly error message - alert('Download failed. Please try again.'); - } finally { - setDownloading(false); - } - }; - - return ( - - ); -}; - -export default DownloadButton; diff --git a/web/src/app/maps/[mapId]/page.tsx b/web/src/app/maps/[mapId]/page.tsx index cd8da52..2c57636 100644 --- a/web/src/app/maps/[mapId]/page.tsx +++ b/web/src/app/maps/[mapId]/page.tsx @@ -30,7 +30,8 @@ import PersonIcon from "@mui/icons-material/Person"; import FlagIcon from "@mui/icons-material/Flag"; import BugReportIcon from "@mui/icons-material/BugReport"; import ContentCopyIcon from "@mui/icons-material/ContentCopy"; -import DownloadButton from "@/app/_components/downloadButton"; +import InsertDriveFileIcon from "@mui/icons-material/InsertDriveFile"; +import DownloadIcon from '@mui/icons-material/Download'; import { hasRole, RolesConstants } from "@/app/ts/Roles"; export default function MapDetails() { @@ -41,6 +42,7 @@ export default function MapDetails() { const [error, setError] = useState(null); const [copySuccess, setCopySuccess] = useState(false); const [roles, setRoles] = useState(RolesConstants.Empty); + const [downloading, setDownloading] = useState(false); useEffect(() => { async function getMap() { @@ -124,6 +126,48 @@ export default function MapDetails() { setCopySuccess(true); }; + + const handleDownload = async () => { + setDownloading(true); + try { + // Fetch the download URL + const res = await fetch(`/api/maps/${mapId}/location`); + if (!res.ok) throw new Error('Failed to fetch download location'); + + const location = await res.text(); + + // Method 1: Try direct download with proper cleanup + try { + const link = document.createElement('a'); + link.href = location.trim(); // Remove any whitespace + link.download = `${map?.DisplayName}.rbxm`; + link.target = '_blank'; // Open in new tab as fallback + link.rel = 'noopener noreferrer'; // Security best practice + + // Ensure the link is properly attached before clicking + document.body.appendChild(link); + link.click(); + + // Clean up after a short delay to ensure download starts + setTimeout(() => { + document.body.removeChild(link); + }, 100); + + } catch (domError) { + console.warn('Direct download failed, trying fallback:', domError); + // Method 2: Fallback - open in new window + window.open(location.trim(), '_blank'); + } + + } catch (err) { + console.error('Download error:', err); + // Optional: Show user-friendly error message + alert('Download failed. Please try again.'); + } finally { + setDownloading(false); + } + }; + const handleCloseSnackbar = () => { setCopySuccess(false); }; @@ -255,6 +299,24 @@ export default function MapDetails() { + {!loading && hasRole(roles,RolesConstants.MapDownload) && ( + + + + Download {map.Creator} + + + + + + + + )} @@ -337,9 +399,6 @@ export default function MapDetails() { > Submit a Mapfix - {hasRole(roles,RolesConstants.MapDownload) && ( - - )} -- 2.49.1 From 023938b8bfd500ea288c5c92249bee8384d7a95d Mon Sep 17 00:00:00 2001 From: Quaternions Date: Mon, 23 Jun 2025 22:56:03 -0700 Subject: [PATCH 2/3] oops --- web/src/app/maps/[mapId]/page.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/src/app/maps/[mapId]/page.tsx b/web/src/app/maps/[mapId]/page.tsx index 2c57636..b0d876f 100644 --- a/web/src/app/maps/[mapId]/page.tsx +++ b/web/src/app/maps/[mapId]/page.tsx @@ -303,7 +303,7 @@ export default function MapDetails() { - Download {map.Creator} + Download Date: Mon, 23 Jun 2025 22:57:49 -0700 Subject: [PATCH 3/3] include CORS limitation in tooltip --- web/src/app/maps/[mapId]/page.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/src/app/maps/[mapId]/page.tsx b/web/src/app/maps/[mapId]/page.tsx index b0d876f..c1d9b75 100644 --- a/web/src/app/maps/[mapId]/page.tsx +++ b/web/src/app/maps/[mapId]/page.tsx @@ -305,7 +305,7 @@ export default function MapDetails() { Download - +