This commit is contained in:
@@ -68,7 +68,7 @@ const CatalogueItem: FC<Props> = ({ item, refetch }) => {
|
||||
</div>
|
||||
<div className="flex justify-end gap-1 items-center mt-1">
|
||||
<Link
|
||||
to={Paths.viewer + `/${item.slug}`}
|
||||
to={Paths.viewerBySlug + `/${item.slug}`}
|
||||
onClick={requestViewerFullscreen}
|
||||
>
|
||||
<div className="size-6 bg-[#EAECF4] rounded-md flex justify-center items-center">
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { type FC, useCallback, useMemo } from "react";
|
||||
import { type FC, useCallback, useMemo, useState } from "react";
|
||||
import { useEditorStore, type ToolType } from "@/pages/editor/store/editorStore";
|
||||
import { useSingleUpload } from "@/pages/uploader/hooks/useUploaderData";
|
||||
import { CloseCircle, Music } from "iconsax-react";
|
||||
@@ -13,30 +13,38 @@ const AudioInput: FC = () => {
|
||||
const { objects, addObject, setSelectedObjectId, setTool, deleteObject } =
|
||||
useEditorStore();
|
||||
const { mutateAsync: uploadFile } = useSingleUpload();
|
||||
const [isUploading, setIsUploading] = useState(false);
|
||||
|
||||
const onDrop = useCallback(
|
||||
async (acceptedFiles: File[]) => {
|
||||
for (const file of acceptedFiles) {
|
||||
try {
|
||||
const result = await uploadFile(file);
|
||||
const audioUrl = result?.data?.url;
|
||||
if (!audioUrl) continue;
|
||||
const audioId = `audio-${Date.now()}-${Math.random()}`;
|
||||
const newAudio = {
|
||||
id: audioId,
|
||||
type: "audio" as ToolType,
|
||||
x: 100,
|
||||
y: 100,
|
||||
width: 320,
|
||||
height: 56,
|
||||
audioUrl,
|
||||
};
|
||||
addObject(newAudio);
|
||||
setSelectedObjectId(newAudio.id);
|
||||
setTool("select");
|
||||
} catch {
|
||||
// TODO: show error toast
|
||||
if (acceptedFiles.length === 0) return;
|
||||
|
||||
setIsUploading(true);
|
||||
try {
|
||||
for (const file of acceptedFiles) {
|
||||
try {
|
||||
const result = await uploadFile(file);
|
||||
const audioUrl = result?.data?.url;
|
||||
if (!audioUrl) continue;
|
||||
const audioId = `audio-${Date.now()}-${Math.random()}`;
|
||||
const newAudio = {
|
||||
id: audioId,
|
||||
type: "audio" as ToolType,
|
||||
x: 100,
|
||||
y: 100,
|
||||
width: 320,
|
||||
height: 56,
|
||||
audioUrl,
|
||||
};
|
||||
addObject(newAudio);
|
||||
setSelectedObjectId(newAudio.id);
|
||||
setTool("select");
|
||||
} catch {
|
||||
// TODO: show error toast
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
setIsUploading(false);
|
||||
}
|
||||
},
|
||||
[addObject, setSelectedObjectId, setTool, uploadFile]
|
||||
@@ -46,6 +54,7 @@ const AudioInput: FC = () => {
|
||||
onDrop,
|
||||
accept: AUDIO_ACCEPT,
|
||||
multiple: true,
|
||||
disabled: isUploading,
|
||||
});
|
||||
|
||||
const audioObjects = useMemo(() => {
|
||||
@@ -63,6 +72,7 @@ const AudioInput: FC = () => {
|
||||
<AudioUploadZone
|
||||
getRootProps={getRootProps}
|
||||
getInputProps={getInputProps}
|
||||
isLoading={isUploading}
|
||||
/>
|
||||
|
||||
{audioObjects.length > 0 && (
|
||||
|
||||
@@ -21,6 +21,11 @@ export const useGetCatalog = () => {
|
||||
});
|
||||
};
|
||||
|
||||
const catalogMongoIdPattern = /^[a-f\d]{24}$/i;
|
||||
|
||||
export const isCatalogMongoId = (value: string) =>
|
||||
catalogMongoIdPattern.test(value);
|
||||
|
||||
export const useGetCatalogById = (id: string) => {
|
||||
return useQuery({
|
||||
queryKey: ["catalog", id],
|
||||
@@ -31,6 +36,15 @@ export const useGetCatalogById = (id: string) => {
|
||||
staleTime: 5 * 60 * 1000,
|
||||
});
|
||||
};
|
||||
|
||||
/** Route param may be Mongo id (editor/admin) or slug (public viewer-style URLs). */
|
||||
export const useGetCatalogByIdOrSlug = (param: string) => {
|
||||
const isId = isCatalogMongoId(param);
|
||||
const byId = useGetCatalogById(isId ? param : "");
|
||||
const bySlug = useGetCatalogBySlug(isId ? "" : param);
|
||||
return isId ? byId : bySlug;
|
||||
};
|
||||
|
||||
export const useGetCatalogBySlug = (slug: string) => {
|
||||
return useQuery({
|
||||
queryKey: ["catalog", slug],
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
import { usePageTitle } from "@/hooks/usePageTitle";
|
||||
import type { DocumentSettings } from "@/pages/editor/store/editorStore";
|
||||
import { useGetCatalogBySlug } from "@/pages/home/hooks/useHomeData";
|
||||
import {
|
||||
useGetCatalogById,
|
||||
useGetCatalogBySlug,
|
||||
} from "@/pages/home/hooks/useHomeData";
|
||||
import { type FC, useEffect, useState } from "react";
|
||||
import { useParams } from "react-router-dom";
|
||||
import BookViewer from "./components/BookViewer";
|
||||
@@ -10,9 +13,16 @@ import { useInitialPagesPreload } from "./hooks/useInitialPagesPreload";
|
||||
import type { PageData } from "./types";
|
||||
import { transformViewerDataToPages } from "./utils/dataTransformer";
|
||||
|
||||
const Viewer: FC = () => {
|
||||
type ViewerProps = {
|
||||
bySlug?: boolean;
|
||||
};
|
||||
const Viewer: FC<ViewerProps> = ({ bySlug = false }) => {
|
||||
const { id } = useParams<{ id: string }>();
|
||||
const { data, isLoading, error: queryError } = useGetCatalogBySlug(id ?? "");
|
||||
const {
|
||||
data,
|
||||
isLoading,
|
||||
error: queryError,
|
||||
} = bySlug ? useGetCatalogBySlug(id ?? "") : useGetCatalogById(id ?? "");
|
||||
usePageTitle(`کاتالوگ ${data?.data?.name}`);
|
||||
const [pages, setPages] = useState<PageData[]>([]);
|
||||
const [documentSettings, setDocumentSettings] = useState<
|
||||
|
||||
Reference in New Issue
Block a user