feat(cms): Add CMS details page and update related components

- Implement new edit marketing page with dynamic routing
- Update CMS and contact us table components with placeholder content
- Add new query hook for fetching CMS details by ID
- Modify CMS service to support fetching individual CMS details
- Update type definitions for CMS-related data structures
- Add initial breadcrumb navigation for edit marketing page
- Prepare infrastructure for future CMS editing functionality
This commit is contained in:
AmirReza Jamali
2025-11-10 09:53:22 +03:30
parent ed18d86960
commit 5640febf40
7 changed files with 210 additions and 155 deletions
+33
View File
@@ -0,0 +1,33 @@
import Loading from "@/app/loading";
import Breadcrumb from "@/components/Breadcrumbs/Breadcrumb";
import { useGetCmsDetails } from "@/hooks/queries/useCmsQueries";
import { BreadcrumbItem } from "@/types/shared";
import { use } from "react";
interface IProps {
params: Promise<{ id: string }>;
}
const EditMarketingPage = async ({ params }: IProps) => {
const { id } = use(params);
const { data, isPending } = useGetCmsDetails(id);
const breadcrumbItems: BreadcrumbItem[] = [
{
href: "/",
name: "Dashboard",
},
{
href: "/marketing",
name: "Marketing",
},
{
href: `/marketing/${id}`,
name: "Edit Marketing",
},
];
if (isPending) return <Loading />;
return (
<>
<Breadcrumb items={breadcrumbItems} />
</>
);
};
+1 -1
View File
@@ -28,7 +28,7 @@ const CmsTable = () => {
columns={columns}
emptyMessage="No Cms were found"
>
Hollo
Cms list will be added
</EmptyListWrapper>
</TableBody>
</Table>
+11 -9
View File
@@ -1,16 +1,12 @@
"use client";
import {
Table,
TableBody,
TableHead,
TableHeader,
TableRow,
} from "@/components/ui/table";
import EmptyListWrapper from "@/components/HOC/EmptyListWrapper";
import { Table, TableHead, TableHeader, TableRow } from "@/components/ui/table";
import TableSkeleton from "@/components/ui/TableSkeleton";
import { useContactUsListPresenter } from "./useContactUsListPresenter";
const ContactUsTable = () => {
const { columns, pathname, router, isPending } = useContactUsListPresenter();
const { columns, pathname, router, isPending, data } =
useContactUsListPresenter();
return (
<div className="flex flex-col rounded-[10px] bg-white px-7.5 pb-4 pt-7.5 shadow-1 dark:bg-gray-dark dark:shadow-card">
<Table>
@@ -28,7 +24,13 @@ const ContactUsTable = () => {
</TableRow>
</TableHeader>
{isPending && <TableSkeleton column={columns.length} />}
<TableBody></TableBody>
<EmptyListWrapper
list={data ?? []}
columns={columns}
emptyMessage="No contact us is submitted"
>
Contact us table will be initialized here
</EmptyListWrapper>
</Table>
</div>
);
@@ -2,7 +2,7 @@
import { useReadAllContactUs } from "@/hooks/queries/useContactUsQuery";
import { usePathname, useRouter } from "next/navigation";
export const useContactUsListPresenter = () => {
const columns: string[] = [];
const columns: string[] = ["row", "actions"];
const pathname = usePathname();
const router = useRouter();
const { data, isPending } = useReadAllContactUs();
+7
View File
@@ -10,6 +10,13 @@ export const useGetCmsList = () => {
queryFn: cmsService.getCms,
});
};
export const useGetCmsDetails = (id: string) => {
const queryKey = useMemo(() => [API_ENDPOINTS.CMS.BASE(id)], [id]);
return useQuery({
queryKey,
queryFn: () => cmsService.getCmsDetails(id),
});
};
export const useCreateCms = () => {
const mutationKey = useMemo(
() => [API_ENDPOINTS.CMS.BASE(), "Create cms"],
+10 -2
View File
@@ -1,10 +1,10 @@
import api from "../axios";
import { API_ENDPOINTS } from "../endpoints";
import { ApiResponse } from "../types";
import { TCmsResponse } from "../types/TCms";
import { TCmsListResponse } from "../types/TCms";
export const cmsService = {
getCms: async (): Promise<ApiResponse<TCmsResponse>> => {
getCms: async (): Promise<ApiResponse<TCmsListResponse>> => {
try {
return (await api.get(API_ENDPOINTS.CMS.BASE())).data;
} catch (error) {
@@ -20,4 +20,12 @@ export const cmsService = {
throw error;
}
},
getCmsDetails: async (id: string) => {
try {
return (await api.get(API_ENDPOINTS.CMS.BASE(id))).data;
} catch (error) {
console.error("Error Caught In CMS Service => getCmsDetails: ", error);
throw error;
}
},
};
+147 -142
View File
@@ -1,155 +1,160 @@
import { z } from "zod";
export const CmsCredentials = z.object({ advantages: z.object({
cards: z.array(
z.object({
description: z.string(),
icon: z.string(),
title: z.string(),
}),
),
export const CmsCredentials = z.object({
advantages: z.object({
cards: z.array(
z.object({
description: z.string(),
icon: z.string(),
title: z.string(),
}),
challenges: z.object({
cards: z.array(
z.object({
description: z.string(),
icon: z.string(),
title: z.string(),
}),
),
),
description: z.string(),
title: z.string(),
}),
challenges: z.object({
cards: z.array(
z.object({
description: z.string(),
icon: z.string(),
title: z.string(),
}),
chart: z.object({
data: z.array(
z.object({
key: z.string(),
value: z.number(),
}),
),
missedAmount: z.string(),
title: z.string(),
),
description: z.string(),
title: z.string(),
}),
chart: z.object({
data: z.array(
z.object({
key: z.string(),
value: z.number(),
}),
contact: z.object({
),
missedAmount: z.string(),
title: z.string(),
}),
contact: z.object({
description: z.string(),
fields: z.array(
z.object({
label: z.string(),
name: z.string(),
placeholder: z.string(),
required: z.boolean(),
}),
),
submitButtonText: z.string(),
title: z.string(),
}),
features: z.object({
cards: z.array(
z.object({
description: z.string(),
fields: z.array(
z.object({
label: z.string(),
name: z.string(),
placeholder: z.string(),
required: z.boolean(),
}),
),
submitButtonText: z.string(),
icon: z.string(),
title: z.string(),
}),
features: z.object({
cards: z.array(
z.object({
description: z.string(),
icon: z.string(),
title: z.string(),
}),
),
description: z.string(),
title: z.string(),
}),
footer: z.object({
copyright: z.string(),
email: z.string(),
location: z.string(),
phone: z.string(),
tagline: z.string(),
}),
hero: z.object({
buttonLink: z.string(),
buttonText: z.string(),
description: z.string(),
gifFile: z.string(),
title: z.string(),
})})
const CmsSchema = z.object({
cms: z.array(
z.object({
advantages: z.object({
cards: z.array(
z.object({
description: z.string(),
icon: z.string(),
title: z.string(),
}),
),
description: z.string(),
title: z.string(),
}),
challenges: z.object({
cards: z.array(
z.object({
description: z.string(),
icon: z.string(),
title: z.string(),
}),
),
description: z.string(),
title: z.string(),
}),
chart: z.object({
data: z.array(
z.object({
key: z.string(),
value: z.number(),
}),
),
missedAmount: z.string(),
title: z.string(),
}),
contact: z.object({
description: z.string(),
fields: z.array(
z.object({
label: z.string(),
name: z.string(),
placeholder: z.string(),
required: z.boolean(),
}),
),
submitButtonText: z.string(),
title: z.string(),
}),
features: z.object({
cards: z.array(
z.object({
description: z.string(),
icon: z.string(),
title: z.string(),
}),
),
description: z.string(),
title: z.string(),
}),
footer: z.object({
copyright: z.string(),
email: z.string(),
location: z.string(),
phone: z.string(),
tagline: z.string(),
}),
hero: z.object({
buttonLink: z.string(),
buttonText: z.string(),
description: z.string(),
gifFile: z.string(),
title: z.string(),
}),
created_at: z.number(),
updated_at: z.number(),
id: z.string(),
key: z.string(),
type: z.string(),
}),
),
),
description: z.string(),
title: z.string(),
}),
footer: z.object({
copyright: z.string(),
email: z.string(),
location: z.string(),
phone: z.string(),
tagline: z.string(),
}),
hero: z.object({
buttonLink: z.string(),
buttonText: z.string(),
description: z.string(),
gifFile: z.string(),
title: z.string(),
}),
});
export type TCmsResponse = z.infer<typeof CmsSchema>;
export type TCmsCredentials = z.infer<typeof CmsCredentials>
const CmsSchema = z.object({
advantages: z.object({
cards: z.array(
z.object({
description: z.string(),
icon: z.string(),
title: z.string(),
}),
),
description: z.string(),
title: z.string(),
}),
challenges: z.object({
cards: z.array(
z.object({
description: z.string(),
icon: z.string(),
title: z.string(),
}),
),
description: z.string(),
title: z.string(),
}),
chart: z.object({
data: z.array(
z.object({
key: z.string(),
value: z.number(),
}),
),
missedAmount: z.string(),
title: z.string(),
}),
contact: z.object({
description: z.string(),
fields: z.array(
z.object({
label: z.string(),
name: z.string(),
placeholder: z.string(),
required: z.boolean(),
}),
),
submitButtonText: z.string(),
title: z.string(),
}),
features: z.object({
cards: z.array(
z.object({
description: z.string(),
icon: z.string(),
title: z.string(),
}),
),
description: z.string(),
title: z.string(),
}),
footer: z.object({
copyright: z.string(),
email: z.string(),
location: z.string(),
phone: z.string(),
tagline: z.string(),
}),
hero: z.object({
buttonLink: z.string(),
buttonText: z.string(),
description: z.string(),
gifFile: z.string(),
title: z.string(),
}),
created_at: z.number(),
updated_at: z.number(),
id: z.string(),
key: z.string(),
type: z.string(),
});
export const cmsListResponseSchema = z.object({
cms: z.array(CmsSchema),
});
export const cmsDetailsResponse = z.object({
cms: CmsSchema,
});
export type TCmsListResponse = z.infer<typeof cmsListResponseSchema>;
export type TCmsDetailsResponse = z.infer<typeof cmsDetailsResponse>
export type TCmsCredentials = z.infer<typeof CmsCredentials>;