mirror of
https://github.com/rgrgogu/new_starr.git
synced 2026-09-27 00:12:54 +08:00
@@ -15,6 +15,7 @@ import { Input } from "@/components/ui/input";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { Textarea } from "@/components/ui/textarea";
|
||||
import { Spinner } from "@/components/ui/spinner";
|
||||
import { Progress } from "@/components/ui/progress";
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
@@ -122,6 +123,7 @@ export default function AddAsset() {
|
||||
const fileRef = useRef(null);
|
||||
const thumbnailRef = useRef(null);
|
||||
const [thumbKey, setThumbKey] = useState(0);
|
||||
const [progress, setProgress] = useState(null); // { phase: 'uploading'|'storing'|'done'|'error', pct } | null
|
||||
|
||||
const {
|
||||
register,
|
||||
@@ -182,6 +184,7 @@ export default function AddAsset() {
|
||||
|
||||
if (hasFileError) return;
|
||||
|
||||
setProgress({ phase: "uploading", pct: 0 });
|
||||
const result = await uploadAsset({
|
||||
file: fileRef.current,
|
||||
thumbnail: thumbnailRef.current ?? undefined,
|
||||
@@ -191,11 +194,20 @@ export default function AddAsset() {
|
||||
is_public: data.is_public === "true",
|
||||
storage_provider: data.storage_provider,
|
||||
createdBy: user?.user_id,
|
||||
onProgress: setProgress,
|
||||
});
|
||||
setProgress(null);
|
||||
|
||||
if (result) { bypassOnce(); navigate(-1); }
|
||||
};
|
||||
|
||||
const progressLabel = {
|
||||
uploading: "Uploading to server…",
|
||||
storing: "Storing to server...",
|
||||
done: "Done.",
|
||||
error: "Upload failed.",
|
||||
}[progress?.phase];
|
||||
|
||||
return (
|
||||
<div className="max-w-2xl mx-auto px-4 py-6 space-y-6">
|
||||
|
||||
@@ -352,6 +364,17 @@ export default function AddAsset() {
|
||||
|
||||
</div>
|
||||
|
||||
{/* ── Upload progress (real — see AdminAssetsContext.uploadAsset) ── */}
|
||||
{progress && (
|
||||
<div className="space-y-1.5">
|
||||
<div className="flex items-center justify-between text-xs text-muted-foreground">
|
||||
<span>{progressLabel}</span>
|
||||
<span>{progress.pct ?? 0}%</span>
|
||||
</div>
|
||||
<Progress value={progress.pct ?? 0} />
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* ── Actions ── */}
|
||||
<div className="flex justify-end gap-3">
|
||||
<Button
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
// modules/admin/pages/assets/ViewAudioAsset.jsx
|
||||
|
||||
import { useEffect } from "react";
|
||||
import { useParams, useNavigate } from "react-router-dom";
|
||||
import { ArrowLeft, Lock, Globe, Music2, Download } from "lucide-react";
|
||||
import { useDateFormat } from "@/hooks/useDateFormat";
|
||||
|
||||
import { useAssets } from "@/contexts/AdminAssetsContext";
|
||||
import { useAssetFetchState } from "@/hooks/useAssetFetchState";
|
||||
import { useAssetPreviewSrc } from "@/hooks/useAssetPreviewSrc";
|
||||
import { downloadAsset } from "@/utils/media.util";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
@@ -34,18 +33,14 @@ export default function ViewAudioAsset() {
|
||||
const navigate = useNavigate();
|
||||
const { fmtDateTime } = useDateFormat();
|
||||
|
||||
const { selectedAsset, loading, fetchAsset } = useAssets();
|
||||
const { asset: selectedAsset, loading, notFound } = useAssetFetchState(assetId);
|
||||
const { src: streamUrl, thumbnailUrl } = useAssetPreviewSrc(selectedAsset, { scope: "admin" });
|
||||
|
||||
useEffect(() => {
|
||||
if (assetId) fetchAsset(assetId);
|
||||
}, [assetId]);
|
||||
|
||||
if (loading) {
|
||||
return <AssetPageLoader />;
|
||||
}
|
||||
|
||||
if (!selectedAsset) {
|
||||
if (notFound) {
|
||||
return (
|
||||
<div className="flex flex-col items-center justify-center h-96 gap-3 text-muted-foreground">
|
||||
<p>Asset not found.</p>
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
// modules/admin/pages/assets/ViewDocumentAsset.jsx
|
||||
|
||||
import { useEffect } from "react";
|
||||
import { useParams, useNavigate } from "react-router-dom";
|
||||
import { ArrowLeft, Lock, Globe, FileText, Download } from "lucide-react";
|
||||
import { useDateFormat } from "@/hooks/useDateFormat";
|
||||
|
||||
import { useAssets } from "@/contexts/AdminAssetsContext";
|
||||
import { useAssetFetchState } from "@/hooks/useAssetFetchState";
|
||||
import { useAssetPreviewSrc } from "@/hooks/useAssetPreviewSrc";
|
||||
import { downloadAsset } from "@/utils/media.util";
|
||||
import { Spinner } from "@/components/ui/spinner";
|
||||
@@ -32,18 +31,14 @@ export default function ViewDocumentAsset() {
|
||||
const navigate = useNavigate();
|
||||
const { fmtDateTime } = useDateFormat();
|
||||
|
||||
const { selectedAsset, loading, fetchAsset } = useAssets();
|
||||
const { asset: selectedAsset, loading, notFound } = useAssetFetchState(assetId);
|
||||
const { src: streamUrl } = useAssetPreviewSrc(selectedAsset, { scope: "admin" });
|
||||
|
||||
useEffect(() => {
|
||||
if (assetId) fetchAsset(assetId);
|
||||
}, [assetId]);
|
||||
|
||||
if (loading) {
|
||||
return <AssetPageLoader />;
|
||||
}
|
||||
|
||||
if (!selectedAsset) {
|
||||
if (notFound) {
|
||||
return (
|
||||
<div className="flex flex-col items-center justify-center h-96 gap-3 text-muted-foreground">
|
||||
<p>Asset not found.</p>
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
// modules/admin/pages/assets/ViewImageAsset.jsx
|
||||
|
||||
import { useEffect } from "react";
|
||||
import { useParams, useNavigate } from "react-router-dom";
|
||||
import { ArrowLeft, Lock, Globe, Download } from "lucide-react";
|
||||
import { useDateFormat } from "@/hooks/useDateFormat";
|
||||
|
||||
import { useAssets } from "@/contexts/AdminAssetsContext";
|
||||
import { useAssetFetchState } from "@/hooks/useAssetFetchState";
|
||||
import { useAssetPreviewSrc } from "@/hooks/useAssetPreviewSrc";
|
||||
import { downloadAsset } from "@/utils/media.util";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
@@ -30,18 +29,14 @@ export default function ViewImageAsset() {
|
||||
const navigate = useNavigate();
|
||||
const { fmtDateTime } = useDateFormat();
|
||||
|
||||
const { selectedAsset, loading, fetchAsset } = useAssets();
|
||||
const { asset: selectedAsset, loading, notFound } = useAssetFetchState(assetId);
|
||||
const { src: streamUrl } = useAssetPreviewSrc(selectedAsset, { scope: "admin" });
|
||||
|
||||
useEffect(() => {
|
||||
if (assetId) fetchAsset(assetId);
|
||||
}, [assetId]);
|
||||
|
||||
if (loading) {
|
||||
return <AssetPageLoader />;
|
||||
}
|
||||
|
||||
if (!selectedAsset) {
|
||||
if (notFound) {
|
||||
return (
|
||||
<div className="flex flex-col items-center justify-center h-96 gap-3 text-muted-foreground">
|
||||
<p>Asset not found.</p>
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
// modules/admin/pages/assets/ViewVideoAsset.jsx
|
||||
|
||||
import { useEffect } from "react";
|
||||
import { useParams, useNavigate } from "react-router-dom";
|
||||
import { ArrowLeft, Lock, Globe, Download } from "lucide-react";
|
||||
import { useDateFormat } from "@/hooks/useDateFormat";
|
||||
|
||||
import { useAssets } from "@/contexts/AdminAssetsContext";
|
||||
import { useAssetFetchState } from "@/hooks/useAssetFetchState";
|
||||
import { useAssetPreviewSrc } from "@/hooks/useAssetPreviewSrc";
|
||||
import { downloadAsset } from "@/utils/media.util";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
@@ -39,18 +38,14 @@ export default function ViewVideoAsset() {
|
||||
const navigate = useNavigate();
|
||||
const { fmtDateTime } = useDateFormat();
|
||||
|
||||
const { selectedAsset, loading, fetchAsset } = useAssets();
|
||||
const { asset: selectedAsset, loading, notFound } = useAssetFetchState(assetId);
|
||||
const { src: streamUrl } = useAssetPreviewSrc(selectedAsset, { scope: "admin" });
|
||||
|
||||
useEffect(() => {
|
||||
if (assetId) fetchAsset(assetId);
|
||||
}, [assetId]);
|
||||
|
||||
if (loading) {
|
||||
return <AssetPageLoader />;
|
||||
}
|
||||
|
||||
if (!selectedAsset) {
|
||||
if (notFound) {
|
||||
return (
|
||||
<div className="flex flex-col items-center justify-center h-96 gap-3 text-muted-foreground">
|
||||
<p>Asset not found.</p>
|
||||
|
||||
Reference in New Issue
Block a user