fix share
This commit is contained in:
parent
ecfa339748
commit
df1ff96e3c
|
|
@ -23,6 +23,8 @@ interface ViewerModalProps {
|
||||||
onClose: () => void;
|
onClose: () => void;
|
||||||
onDelete?: (assetId: string) => void;
|
onDelete?: (assetId: string) => void;
|
||||||
onShare?: (assetId: string) => void;
|
onShare?: (assetId: string) => void;
|
||||||
|
shareToken?: string;
|
||||||
|
sharePassword?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function ViewerModal({
|
export default function ViewerModal({
|
||||||
|
|
@ -31,10 +33,13 @@ export default function ViewerModal({
|
||||||
onClose,
|
onClose,
|
||||||
onDelete,
|
onDelete,
|
||||||
onShare,
|
onShare,
|
||||||
|
shareToken,
|
||||||
|
sharePassword,
|
||||||
}: ViewerModalProps) {
|
}: ViewerModalProps) {
|
||||||
const [currentUrl, setCurrentUrl] = useState<string>('');
|
const [currentUrl, setCurrentUrl] = useState<string>('');
|
||||||
const [loading, setLoading] = useState(true);
|
const [loading, setLoading] = useState(true);
|
||||||
const [currentIndex, setCurrentIndex] = useState(-1);
|
const [currentIndex, setCurrentIndex] = useState(-1);
|
||||||
|
const [isBlobUrl, setIsBlobUrl] = useState(false);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (asset) {
|
if (asset) {
|
||||||
|
|
@ -45,7 +50,7 @@ export default function ViewerModal({
|
||||||
|
|
||||||
// Cleanup blob URL on unmount or asset change
|
// Cleanup blob URL on unmount or asset change
|
||||||
return () => {
|
return () => {
|
||||||
if (currentUrl) {
|
if (currentUrl && isBlobUrl) {
|
||||||
URL.revokeObjectURL(currentUrl);
|
URL.revokeObjectURL(currentUrl);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -80,13 +85,26 @@ export default function ViewerModal({
|
||||||
try {
|
try {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
// Revoke previous blob URL to prevent memory leaks
|
// Revoke previous blob URL to prevent memory leaks
|
||||||
if (currentUrl) {
|
if (currentUrl && isBlobUrl) {
|
||||||
URL.revokeObjectURL(currentUrl);
|
URL.revokeObjectURL(currentUrl);
|
||||||
}
|
}
|
||||||
// Load media through backend proxy with auth
|
|
||||||
const blob = await api.getMediaBlob(asset.id, 'original');
|
let url: string;
|
||||||
const url = URL.createObjectURL(blob);
|
let isBlob: boolean;
|
||||||
|
|
||||||
|
// If viewing shared content, use share download URL (pre-signed S3 URL)
|
||||||
|
if (shareToken) {
|
||||||
|
url = await api.getShareDownloadUrl(shareToken, asset.id, 'original', sharePassword);
|
||||||
|
isBlob = false;
|
||||||
|
} else {
|
||||||
|
// Otherwise use authenticated media endpoint with blob
|
||||||
|
const blob = await api.getMediaBlob(asset.id, 'original');
|
||||||
|
url = URL.createObjectURL(blob);
|
||||||
|
isBlob = true;
|
||||||
|
}
|
||||||
|
|
||||||
setCurrentUrl(url);
|
setCurrentUrl(url);
|
||||||
|
setIsBlobUrl(isBlob);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Failed to load media:', error);
|
console.error('Failed to load media:', error);
|
||||||
} finally {
|
} finally {
|
||||||
|
|
|
||||||
|
|
@ -171,6 +171,8 @@ export default function ShareViewPage() {
|
||||||
asset={viewerOpen ? asset : null}
|
asset={viewerOpen ? asset : null}
|
||||||
assets={[asset]}
|
assets={[asset]}
|
||||||
onClose={() => setViewerOpen(false)}
|
onClose={() => setViewerOpen(false)}
|
||||||
|
shareToken={token}
|
||||||
|
sharePassword={password}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</Container>
|
</Container>
|
||||||
|
|
|
||||||
|
|
@ -25,11 +25,17 @@ class ApiClient {
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
// Add auth token to requests
|
// Add auth token to requests (except for public share endpoints)
|
||||||
this.client.interceptors.request.use((config) => {
|
this.client.interceptors.request.use((config) => {
|
||||||
const token = localStorage.getItem('access_token');
|
// Skip auth for public share endpoints
|
||||||
if (token) {
|
const isShareEndpoint = config.url?.startsWith('/shares/') &&
|
||||||
config.headers.Authorization = `Bearer ${token}`;
|
!config.url?.includes('/revoke');
|
||||||
|
|
||||||
|
if (!isShareEndpoint) {
|
||||||
|
const token = localStorage.getItem('access_token');
|
||||||
|
if (token) {
|
||||||
|
config.headers.Authorization = `Bearer ${token}`;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return config;
|
return config;
|
||||||
});
|
});
|
||||||
|
|
@ -41,8 +47,10 @@ class ApiClient {
|
||||||
if (error.response?.status === 401) {
|
if (error.response?.status === 401) {
|
||||||
localStorage.removeItem('access_token');
|
localStorage.removeItem('access_token');
|
||||||
localStorage.removeItem('refresh_token');
|
localStorage.removeItem('refresh_token');
|
||||||
// Redirect only if not already on login/register page
|
// Redirect only if not on login/register/share pages
|
||||||
if (!['/login', '/register'].includes(window.location.pathname)) {
|
const path = window.location.pathname;
|
||||||
|
const isPublicPage = ['/login', '/register'].includes(path) || path.startsWith('/share/');
|
||||||
|
if (!isPublicPage) {
|
||||||
window.location.href = '/login';
|
window.location.href = '/login';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue