This commit is contained in:
rgrgogu
2026-05-12 12:47:13 +08:00
parent 1d94f27e61
commit 6e98ff0b5d
16 changed files with 211 additions and 20 deletions
+175
View File
@@ -0,0 +1,175 @@
import { createContext, useCallback, useContext, useState } from "react";
import api from "@/utils/api.util";
import { toast } from "sonner";
const AssetsContext = createContext(null);
export function useAssets() {
const ctx = useContext(AssetsContext);
if (!ctx) throw new Error("useAssets must be used within an AssetsProvider");
return ctx;
}
export function AssetsProvider({ children }) {
const [assets, setAssets] = useState([]);
const [pagination, setPagination] = useState(null);
const [selectedAsset, setSelectedAsset] = useState(null);
const [loading, setLoading] = useState(false);
const request = useCallback(async (fn) => {
setLoading(true);
try {
return await fn();
} catch (err) {
const message = err?.response?.data?.message ?? "Something went wrong.";
toast.error(message);
return null;
} finally {
setLoading(false);
}
}, []);
// ─── GET /api/admin/assets ────────────────────────────────────────────────
const fetchAssets = useCallback(
(params = {}) =>
request(async () => {
const res = await api.get("/admin/assets", { params });
setAssets(res.data?.result?.data ?? []);
setPagination(res.data?.result?.pagination ?? null);
return res.data;
}),
[request]
);
// ─── GET /api/admin/assets/:assetId ───────────────────────────────────────
const fetchAsset = useCallback(
(assetId) =>
request(async () => {
const res = await api.get(`/admin/assets/${assetId}`);
setSelectedAsset(res.data?.result?.data ?? null);
return res.data;
}),
[request]
);
// ─── POST /api/admin/assets ───────────────────────────────────────────────
// fields: { file (File), thumbnail? (File), uploadedBy, display_name,
// description, owner_type, owner_id, is_public, access_level,
// storage_provider, storage_bucket, storage_key }
const uploadAsset = useCallback(
({ file, thumbnail, ...rest }) =>
request(async () => {
const form = new FormData();
form.append("file", file);
if (thumbnail) form.append("thumbnail", thumbnail);
Object.entries(rest).forEach(([k, v]) => {
if (v !== undefined && v !== null) form.append(k, v);
});
const res = await api.post("/admin/assets", form, {
headers: { "Content-Type": "multipart/form-data" },
});
const asset = res.data?.result?.data ?? null;
if (asset) setAssets((prev) => [asset, ...prev]);
return res.data;
}),
[request]
);
// ─── PATCH /api/admin/assets/:assetId/thumbnail ───────────────────────────
const updateThumbnail = useCallback(
(assetId, thumbnailFile) =>
request(async () => {
const form = new FormData();
form.append("thumbnail", thumbnailFile);
const res = await api.patch(`/admin/assets/${assetId}/thumbnail`, form, {
headers: { "Content-Type": "multipart/form-data" },
});
const asset = res.data?.result?.data ?? null;
if (asset) {
setAssets((prev) => prev.map((a) => (a.asset_id === assetId ? asset : a)));
setSelectedAsset((prev) => (prev?.asset_id === assetId ? asset : prev));
}
return res.data;
}),
[request]
);
// ─── PUT /api/admin/assets/:assetId ───────────────────────────────────────
// Allowed: display_name, description, owner_type, owner_id, is_public,
// access_level, thumbnail_url, width, height, duration,
// frame_rate, bitrate, video_codec, audio_codec
const updateAsset = useCallback(
(assetId, fields) =>
request(async () => {
const res = await api.put(`/admin/assets/${assetId}`, fields);
const asset = res.data?.result?.data ?? null;
if (asset) {
setAssets((prev) => prev.map((a) => (a.asset_id === assetId ? asset : a)));
setSelectedAsset((prev) => (prev?.asset_id === assetId ? asset : prev));
}
return res.data;
}),
[request]
);
// ─── DELETE /api/admin/assets/:assetId ────────────────────────────────────
const deleteAsset = useCallback(
(assetId, { deletedBy } = {}) =>
request(async () => {
const res = await api.delete(`/admin/assets/${assetId}`, {
data: { deletedBy },
});
setAssets((prev) => prev.filter((a) => a.asset_id !== assetId));
setSelectedAsset((prev) => (prev?.asset_id === assetId ? null : prev));
return res.data;
}),
[request]
);
// ─── DELETE /api/admin/assets (bulk) ──────────────────────────────────────
const deleteAssets = useCallback(
(ids = [], { deletedBy } = {}) =>
request(async () => {
const res = await api.delete("/admin/assets", {
data: { ids, deletedBy },
});
setAssets((prev) => prev.filter((a) => !ids.includes(a.asset_id)));
return res.data;
}),
[request]
);
// ─── PATCH /api/admin/assets/:assetId/restore ─────────────────────────────
const restoreAsset = useCallback(
(assetId) =>
request(async () => {
const res = await api.patch(`/admin/assets/${assetId}/restore`);
const asset = res.data?.result?.data ?? null;
if (asset) setAssets((prev) => prev.map((a) => (a.asset_id === assetId ? asset : a)));
return res.data;
}),
[request]
);
return (
<AssetsContext.Provider value={{
assets,
pagination,
selectedAsset,
loading,
setSelectedAsset,
fetchAssets,
fetchAsset,
uploadAsset,
updateThumbnail,
updateAsset,
deleteAsset,
deleteAssets,
restoreAsset,
}}>
{children}
</AssetsContext.Provider>
);
}