catalogue service , hook
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
import GridWrapper from "@/components/GridWrapper";
|
||||
import { usePageTitle } from "@/hooks/usePageTitle";
|
||||
import { type FC } from "react";
|
||||
import { useGetCatalog } from "../home/hooks/useHomeData";
|
||||
import { useGetCatalog } from "./hooks/useCatalogueData";
|
||||
import ButtonAddCatalogue from "./components/ButtonAddCatalogue";
|
||||
import CatalogueGridSkeleton from "./components/CatalogueGridSkeleton";
|
||||
import CatalogueItem from "./components/CatalogueItem";
|
||||
|
||||
@@ -2,7 +2,7 @@ import { toast } from "@/components/Toast";
|
||||
import TrashWithConfrim from "@/components/TrashWithConfrim";
|
||||
import { Paths } from "@/config/Paths";
|
||||
import { extractErrorMessage } from "@/helpers/utils";
|
||||
import { useDleteCatalog } from "@/pages/home/hooks/useHomeData";
|
||||
import { useDleteCatalog } from "@/pages/catalogue/hooks/useCatalogueData";
|
||||
import { requestViewerFullscreen } from "@/pages/viewer/utils/viewerFullscreen";
|
||||
import { Edit, Eye, Share } from "iconsax-react";
|
||||
import moment from "moment-jalaali";
|
||||
|
||||
@@ -1,6 +1,127 @@
|
||||
import { useMutation, useQuery } from "@tanstack/react-query";
|
||||
import { useCallback, useEffect, useRef, useState } from "react";
|
||||
import * as api from "../service/CatalogueService";
|
||||
|
||||
export const useCreateCatalog = () => {
|
||||
return useMutation({
|
||||
mutationFn: api.createCatalog,
|
||||
});
|
||||
};
|
||||
|
||||
export const useDleteCatalog = () => {
|
||||
return useMutation({
|
||||
mutationFn: (id: string) => api.deleteCatalogById(id),
|
||||
});
|
||||
};
|
||||
|
||||
export const useGetCatalog = () => {
|
||||
return useQuery({
|
||||
queryKey: ["catalogs"],
|
||||
queryFn: api.getCatalogs,
|
||||
});
|
||||
};
|
||||
|
||||
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],
|
||||
queryFn: () => api.getCatalogById(id),
|
||||
enabled: !!id,
|
||||
// جلوگیری از بازنویسی state محلی با refetch هنگام فوکوس پنجره (مثلاً دو کاربر همزمان)
|
||||
refetchOnWindowFocus: false,
|
||||
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],
|
||||
queryFn: () => api.getCatalogBySlug(slug),
|
||||
enabled: !!slug,
|
||||
// جلوگیری از بازنویسی state محلی با refetch هنگام فوکوس پنجره (مثلاً دو کاربر همزمان)
|
||||
refetchOnWindowFocus: false,
|
||||
staleTime: 5 * 60 * 1000,
|
||||
});
|
||||
};
|
||||
|
||||
export const useUpdateCatalog = () => {
|
||||
const mutation = useMutation({
|
||||
mutationFn: api.updateCatalog,
|
||||
});
|
||||
|
||||
const timeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);
|
||||
const pendingParamsRef = useRef<
|
||||
Parameters<typeof api.updateCatalog>[0] | null
|
||||
>(null);
|
||||
const [isScheduledSaving, setIsScheduledSaving] = useState(false);
|
||||
|
||||
const cancelPendingUpdate = useCallback(() => {
|
||||
if (timeoutRef.current) {
|
||||
clearTimeout(timeoutRef.current);
|
||||
timeoutRef.current = null;
|
||||
}
|
||||
pendingParamsRef.current = null;
|
||||
setIsScheduledSaving(false);
|
||||
}, []);
|
||||
|
||||
const scheduleUpdate = useCallback(
|
||||
(params: Parameters<typeof api.updateCatalog>[0], delayMs = 3000) => {
|
||||
if (timeoutRef.current) {
|
||||
clearTimeout(timeoutRef.current);
|
||||
}
|
||||
pendingParamsRef.current = params;
|
||||
setIsScheduledSaving(true);
|
||||
|
||||
timeoutRef.current = setTimeout(() => {
|
||||
const pendingParams = pendingParamsRef.current;
|
||||
timeoutRef.current = null;
|
||||
pendingParamsRef.current = null;
|
||||
setIsScheduledSaving(false);
|
||||
if (pendingParams) {
|
||||
mutation.mutate(pendingParams);
|
||||
}
|
||||
}, delayMs);
|
||||
},
|
||||
[mutation],
|
||||
);
|
||||
|
||||
useEffect(
|
||||
() => () => {
|
||||
if (timeoutRef.current) {
|
||||
clearTimeout(timeoutRef.current);
|
||||
timeoutRef.current = null;
|
||||
}
|
||||
// اگر کاربر قبل از پایان debounce از ادیتور خارج شد،
|
||||
// آخرین تغییرات معلق را همان لحظه ذخیره کن.
|
||||
if (pendingParamsRef.current) {
|
||||
mutation.mutate(pendingParamsRef.current);
|
||||
pendingParamsRef.current = null;
|
||||
}
|
||||
setIsScheduledSaving(false);
|
||||
},
|
||||
[mutation],
|
||||
);
|
||||
|
||||
return {
|
||||
...mutation,
|
||||
scheduleUpdate,
|
||||
cancelPendingUpdate,
|
||||
isSaving: isScheduledSaving || mutation.isPending,
|
||||
};
|
||||
};
|
||||
|
||||
export const usePurchaseInitate = () => {
|
||||
return useMutation({
|
||||
mutationFn: api.purchaseInitate,
|
||||
|
||||
@@ -1,5 +1,47 @@
|
||||
import axios from "@/config/axios";
|
||||
import type { CatalogResponseType, PurchaseInitiate } from "../types/Types";
|
||||
import type {
|
||||
CatalogByIdResponseType,
|
||||
CatalogResponseType,
|
||||
CreateCatalogParamsType,
|
||||
PurchaseInitiate,
|
||||
UpdateCatalogParamsType,
|
||||
} from "../types/Types";
|
||||
|
||||
export const createCatalog = async (params: CreateCatalogParamsType) => {
|
||||
const { data } = await axios.post("/admin/catalogue", params);
|
||||
return data;
|
||||
};
|
||||
|
||||
export const getCatalogs = async () => {
|
||||
const { data } = await axios.get<CatalogResponseType>("/admin/catalogue");
|
||||
return data;
|
||||
};
|
||||
|
||||
export const getCatalogById = async (id: string) => {
|
||||
const { data } = await axios.get<CatalogByIdResponseType>(
|
||||
`/admin/catalogue/${id}`,
|
||||
);
|
||||
return data;
|
||||
};
|
||||
|
||||
export const getCatalogBySlug = async (slug: string) => {
|
||||
const { data } = await axios.get<CatalogByIdResponseType>(
|
||||
`/public/catalogue/slug/${slug}`,
|
||||
);
|
||||
return data;
|
||||
};
|
||||
|
||||
export const updateCatalog = async (params: UpdateCatalogParamsType) => {
|
||||
const { data } = await axios.patch(`/admin/catalogue/${params.id}`, {
|
||||
content: params.content,
|
||||
});
|
||||
return data;
|
||||
};
|
||||
|
||||
export const deleteCatalogById = async (id: string) => {
|
||||
const { data } = await axios.delete(`/admin/catalogue/${id}`);
|
||||
return data;
|
||||
};
|
||||
|
||||
export const purchaseInitate = async (params: PurchaseInitiate) => {
|
||||
const { data } = await axios.post(
|
||||
|
||||
@@ -16,3 +16,16 @@ export type CatalogByIdResponseType = BaseResponse<CatalogItemType>;
|
||||
export type PurchaseInitiate = {
|
||||
count: number;
|
||||
};
|
||||
|
||||
export type CreateCatalogParamsType = {
|
||||
name: string;
|
||||
slug: string;
|
||||
size: string;
|
||||
content?: string;
|
||||
id?: string;
|
||||
};
|
||||
|
||||
export type UpdateCatalogParamsType = {
|
||||
id: string;
|
||||
content: string;
|
||||
};
|
||||
|
||||
@@ -4,7 +4,10 @@ import Konva from "konva";
|
||||
import { type FC, useEffect, useRef, useState } from "react";
|
||||
import { useParams } from "react-router-dom";
|
||||
import { useSharedStore } from "@/shared/store/sharedStore";
|
||||
import { useGetCatalogById, useUpdateCatalog } from "../home/hooks/useHomeData";
|
||||
import {
|
||||
useGetCatalogById,
|
||||
useUpdateCatalog,
|
||||
} from "@/pages/catalogue/hooks/useCatalogueData";
|
||||
import EditorCanvas from "./components/EditorCanvas";
|
||||
import EditorSidebar from "./components/EditorSidebar";
|
||||
import LayersPanel from "./components/LayersPanel";
|
||||
|
||||
@@ -6,11 +6,11 @@ import { toast } from "@/components/Toast";
|
||||
import { Paths } from "@/config/Paths";
|
||||
import { clx, extractErrorMessage } from "@/helpers/utils";
|
||||
import { usePageTitle } from "@/hooks/usePageTitle";
|
||||
import { useCreateCatalog } from "@/pages/catalogue/hooks/useCatalogueData";
|
||||
import { ArrowLeft, DocumentText } from "iconsax-react";
|
||||
import { useState, type FC } from "react";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import DirectLogin from "../auth/components/DirectLogin";
|
||||
import { useCreateCatalog } from "./hooks/useHomeData";
|
||||
|
||||
const CATALOG_SIZES = [
|
||||
{ id: "a4", label: "A4" },
|
||||
@@ -71,7 +71,7 @@ const Home: FC = () => {
|
||||
type="button"
|
||||
onClick={() => setActive(id)}
|
||||
className={clx(
|
||||
"flex w-full h-[126px] sm:w-[120px] cursor-pointer items-center justify-center rounded-[20px] border border-border sm:h-[146px] sm:w-[140px] lg:h-[166px] lg:w-[160px]",
|
||||
"flex w-full h-[126px] cursor-pointer items-center justify-center rounded-[20px] border border-border sm:h-[146px] sm:w-[140px] lg:h-[166px] lg:w-[160px]",
|
||||
active === id && "border-black!",
|
||||
)}
|
||||
>
|
||||
|
||||
@@ -1,123 +0,0 @@
|
||||
import { useMutation, useQuery } from "@tanstack/react-query";
|
||||
import { useCallback, useEffect, useRef, useState } from "react";
|
||||
import * as api from "../service/HomeService";
|
||||
|
||||
export const useCreateCatalog = () => {
|
||||
return useMutation({
|
||||
mutationFn: api.createCatalog,
|
||||
});
|
||||
};
|
||||
|
||||
export const useDleteCatalog = () => {
|
||||
return useMutation({
|
||||
mutationFn: (id: string) => api.deleteCatalogById(id),
|
||||
});
|
||||
};
|
||||
|
||||
export const useGetCatalog = () => {
|
||||
return useQuery({
|
||||
queryKey: ["catalogs"],
|
||||
queryFn: api.getCatalogs,
|
||||
});
|
||||
};
|
||||
|
||||
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],
|
||||
queryFn: () => api.getCatalogById(id),
|
||||
enabled: !!id,
|
||||
// جلوگیری از بازنویسی state محلی با refetch هنگام فوکوس پنجره (مثلاً دو کاربر همزمان)
|
||||
refetchOnWindowFocus: false,
|
||||
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],
|
||||
queryFn: () => api.getCatalogBySlug(slug),
|
||||
enabled: !!slug,
|
||||
// جلوگیری از بازنویسی state محلی با refetch هنگام فوکوس پنجره (مثلاً دو کاربر همزمان)
|
||||
refetchOnWindowFocus: false,
|
||||
staleTime: 5 * 60 * 1000,
|
||||
});
|
||||
};
|
||||
|
||||
export const useUpdateCatalog = () => {
|
||||
const mutation = useMutation({
|
||||
mutationFn: api.updateCatalog,
|
||||
});
|
||||
|
||||
const timeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);
|
||||
const pendingParamsRef = useRef<
|
||||
Parameters<typeof api.updateCatalog>[0] | null
|
||||
>(null);
|
||||
const [isScheduledSaving, setIsScheduledSaving] = useState(false);
|
||||
|
||||
const cancelPendingUpdate = useCallback(() => {
|
||||
if (timeoutRef.current) {
|
||||
clearTimeout(timeoutRef.current);
|
||||
timeoutRef.current = null;
|
||||
}
|
||||
pendingParamsRef.current = null;
|
||||
setIsScheduledSaving(false);
|
||||
}, []);
|
||||
|
||||
const scheduleUpdate = useCallback(
|
||||
(params: Parameters<typeof api.updateCatalog>[0], delayMs = 3000) => {
|
||||
if (timeoutRef.current) {
|
||||
clearTimeout(timeoutRef.current);
|
||||
}
|
||||
pendingParamsRef.current = params;
|
||||
setIsScheduledSaving(true);
|
||||
|
||||
timeoutRef.current = setTimeout(() => {
|
||||
const pendingParams = pendingParamsRef.current;
|
||||
timeoutRef.current = null;
|
||||
pendingParamsRef.current = null;
|
||||
setIsScheduledSaving(false);
|
||||
if (pendingParams) {
|
||||
mutation.mutate(pendingParams);
|
||||
}
|
||||
}, delayMs);
|
||||
},
|
||||
[mutation],
|
||||
);
|
||||
|
||||
useEffect(
|
||||
() => () => {
|
||||
if (timeoutRef.current) {
|
||||
clearTimeout(timeoutRef.current);
|
||||
timeoutRef.current = null;
|
||||
}
|
||||
// اگر کاربر قبل از پایان debounce از ادیتور خارج شد،
|
||||
// آخرین تغییرات معلق را همان لحظه ذخیره کن.
|
||||
if (pendingParamsRef.current) {
|
||||
mutation.mutate(pendingParamsRef.current);
|
||||
pendingParamsRef.current = null;
|
||||
}
|
||||
setIsScheduledSaving(false);
|
||||
},
|
||||
[mutation],
|
||||
);
|
||||
|
||||
return {
|
||||
...mutation,
|
||||
scheduleUpdate,
|
||||
cancelPendingUpdate,
|
||||
isSaving: isScheduledSaving || mutation.isPending,
|
||||
};
|
||||
};
|
||||
@@ -1,45 +0,0 @@
|
||||
import axios from "@/config/axios";
|
||||
import type {
|
||||
CatalogByIdResponseType,
|
||||
CatalogResponseType,
|
||||
} from "@/pages/catalogue/types/Types";
|
||||
import type {
|
||||
CreateCatalogParamsType,
|
||||
UpdateCatalogParamsType,
|
||||
} from "../types/Types";
|
||||
|
||||
export const createCatalog = async (params: CreateCatalogParamsType) => {
|
||||
const { data } = await axios.post("/admin/catalogue", params);
|
||||
return data;
|
||||
};
|
||||
|
||||
export const getCatalogs = async () => {
|
||||
const { data } = await axios.get<CatalogResponseType>("/admin/catalogue");
|
||||
return data;
|
||||
};
|
||||
|
||||
export const getCatalogById = async (id: string) => {
|
||||
const { data } = await axios.get<CatalogByIdResponseType>(
|
||||
`/admin/catalogue/${id}`,
|
||||
);
|
||||
return data;
|
||||
};
|
||||
|
||||
export const getCatalogBySlug = async (slug: string) => {
|
||||
const { data } = await axios.get<CatalogByIdResponseType>(
|
||||
`/public/catalogue/slug/${slug}`,
|
||||
);
|
||||
return data;
|
||||
};
|
||||
|
||||
export const updateCatalog = async (params: UpdateCatalogParamsType) => {
|
||||
const { data } = await axios.patch(`/admin/catalogue/${params.id}`, {
|
||||
content: params.content,
|
||||
});
|
||||
return data;
|
||||
};
|
||||
|
||||
export const deleteCatalogById = async (id: string) => {
|
||||
const { data } = await axios.delete(`/admin/catalogue/${id}`);
|
||||
return data;
|
||||
};
|
||||
@@ -1,12 +0,0 @@
|
||||
export type CreateCatalogParamsType = {
|
||||
name: string;
|
||||
slug: string;
|
||||
size: string;
|
||||
content?: string;
|
||||
id?: string;
|
||||
};
|
||||
|
||||
export type UpdateCatalogParamsType = {
|
||||
id: string;
|
||||
content: string;
|
||||
};
|
||||
@@ -3,7 +3,7 @@ import type { DocumentSettings } from "@/pages/editor/store/editorStore";
|
||||
import {
|
||||
useGetCatalogById,
|
||||
useGetCatalogBySlug,
|
||||
} from "@/pages/home/hooks/useHomeData";
|
||||
} from "@/pages/catalogue/hooks/useCatalogueData";
|
||||
import { type FC, useEffect, useState } from "react";
|
||||
import { useParams } from "react-router-dom";
|
||||
import BookViewer from "./components/BookViewer";
|
||||
|
||||
Reference in New Issue
Block a user