Commit 1334e92b authored by Lê Bảo Hồng Đức's avatar Lê Bảo Hồng Đức

fix

parent d9a52db6
......@@ -127,6 +127,7 @@ const orvalConfig = async () => {
'NewsletterSubscription',
'SiteInformation',
'Logo',
'Banner',
],
},
},
......
This diff is collapsed.
/**
* Generated by orval v8.0.0-rc.0 🍺
* Do not edit manually.
* Backend Template
* Coded by Meu TEAM
* OpenAPI spec version: 1.0.0
*/
import type { ApiResponse } from './apiResponse';
import type { DeleteBannerId200AllOf } from './deleteBannerId200AllOf';
export type DeleteBannerId200 = ApiResponse & DeleteBannerId200AllOf;
/**
* Generated by orval v8.0.0-rc.0 🍺
* Do not edit manually.
* Backend Template
* Coded by Meu TEAM
* OpenAPI spec version: 1.0.0
*/
export type DeleteBannerId200AllOf = {
responseData?: boolean;
};
/**
* Generated by orval v8.0.0-rc.0 🍺
* Do not edit manually.
* Backend Template
* Coded by Meu TEAM
* OpenAPI spec version: 1.0.0
*/
import type { ApiResponse } from './apiResponse';
import type { GetBannerId200AllOf } from './getBannerId200AllOf';
export type GetBannerId200 = ApiResponse & GetBannerId200AllOf;
/**
* Generated by orval v8.0.0-rc.0 🍺
* Do not edit manually.
* Backend Template
* Coded by Meu TEAM
* OpenAPI spec version: 1.0.0
*/
import type { Banner } from './banner';
export type GetBannerId200AllOf = {
responseData?: Banner;
};
/**
* Generated by orval v8.0.0-rc.0 🍺
* Do not edit manually.
* Backend Template
* Coded by Meu TEAM
* OpenAPI spec version: 1.0.0
*/
import type { FiltersParameter } from './filtersParameter';
import type { SortFieldParameter } from './sortFieldParameter';
import type { SortOrderParameter } from './sortOrderParameter';
import type { PageParameter } from './pageParameter';
import type { PageSizeParameter } from './pageSizeParameter';
export type GetBannerParams = {
/**
* filter, visit https://www.npmjs.com/package/sequelize-api-paginate for syntax
*/
filters?: FiltersParameter;
/**
* sortField, visit https://www.npmjs.com/package/sequelize-api-paginate for syntax
*/
sortField?: SortFieldParameter;
/**
* sort order, visit https://www.npmjs.com/package/sequelize-api-paginate for syntax
*/
sortOrder?: SortOrderParameter;
/**
* page, visit https://www.npmjs.com/package/sequelize-api-paginate for syntax
* @minimum 1
*/
page?: PageParameter;
/**
* pageSize, visit https://www.npmjs.com/package/sequelize-api-paginate for syntax
* @minimum 1
*/
pageSize?: PageSizeParameter;
};
......@@ -45,6 +45,8 @@ export * from './deleteApiV10CategoryId200AllOf';
export * from './deleteApiV10ContactId200';
export * from './deleteApiV10ContactId200AllOf';
export * from './deleteApprovalParams';
export * from './deleteBannerId200';
export * from './deleteBannerId200AllOf';
export * from './deleteCategoryId200';
export * from './deleteCategoryId200AllOf';
export * from './deleteConfigParams';
......@@ -106,6 +108,9 @@ export * from './getApiV10VideoId200';
export * from './getApiV10VideoId200AllOf';
export * from './getApiV10VideoParams';
export * from './getApprovalParams';
export * from './getBannerId200';
export * from './getBannerId200AllOf';
export * from './getBannerParams';
export * from './getCategoryId200';
export * from './getCategoryId200AllOf';
export * from './getCategoryParams';
......@@ -266,6 +271,8 @@ export * from './postApiV10PageConfigBody';
export * from './postApiV10Video200';
export * from './postApiV10Video200AllOf';
export * from './postAuthForgotPasswordBody';
export * from './postBanner200';
export * from './postBanner200AllOf';
export * from './postCategory';
export * from './postCategory200';
export * from './postCategory200AllOf';
......@@ -314,6 +321,8 @@ export * from './putApiV10SiteInformation200';
export * from './putApiV10SiteInformation200AllOf';
export * from './putAuthAssignBusinessInterestBody';
export * from './putAuthUpdatePasswordBody';
export * from './putBannerId200';
export * from './putBannerId200AllOf';
export * from './putCategoryId200';
export * from './putCategoryId200AllOf';
export * from './putConfigParams';
......
/**
* Generated by orval v8.0.0-rc.0 🍺
* Do not edit manually.
* Backend Template
* Coded by Meu TEAM
* OpenAPI spec version: 1.0.0
*/
import type { ApiResponse } from './apiResponse';
import type { PostBanner200AllOf } from './postBanner200AllOf';
export type PostBanner200 = ApiResponse & PostBanner200AllOf;
/**
* Generated by orval v8.0.0-rc.0 🍺
* Do not edit manually.
* Backend Template
* Coded by Meu TEAM
* OpenAPI spec version: 1.0.0
*/
import type { Banner } from './banner';
export type PostBanner200AllOf = {
responseData?: Banner;
};
/**
* Generated by orval v8.0.0-rc.0 🍺
* Do not edit manually.
* Backend Template
* Coded by Meu TEAM
* OpenAPI spec version: 1.0.0
*/
import type { ApiResponse } from './apiResponse';
import type { PutBannerId200AllOf } from './putBannerId200AllOf';
export type PutBannerId200 = ApiResponse & PutBannerId200AllOf;
/**
* Generated by orval v8.0.0-rc.0 🍺
* Do not edit manually.
* Backend Template
* Coded by Meu TEAM
* OpenAPI spec version: 1.0.0
*/
import type { Banner } from './banner';
export type PutBannerId200AllOf = {
responseData?: Banner;
};
......@@ -44,7 +44,10 @@ import {
putSiteInformation,
} from "@/api/endpoints/site-information";
import { deleteLogoId, postLogo, putLogoId } from "@/api/endpoints/logo";
import { deleteBannerId, getBanner, postBanner, putBannerId } from "@/api/endpoints/banner";
import type {
Banner,
BannerMutate,
SiteInformationBranch,
SiteInformationBranchMutate,
SiteInformationData,
......@@ -52,6 +55,7 @@ import type {
SiteInformationSocialMutate,
} from "@/api/models";
import type { AdminMediaItem } from "@/mockdata/admin-news";
import { fetchCmsFileById, toAdminMediaItem } from "@/lib/api/files";
import {
type BaseConfigBannerItem,
type BaseConfigBranchItem,
......@@ -83,6 +87,13 @@ type LogoMediaItem = AdminMediaItem & {
logoId?: string;
};
type PageEnvelope<T> = {
rows?: T[];
count?: number;
page?: number;
pageSize?: number;
};
type ConfigItemForm = {
name: string;
imageId: string;
......@@ -158,6 +169,27 @@ function mapConfigSocialToApi(social: BaseConfigSocialItem): SiteInformationSoci
};
}
function mapApiBannerToConfig(banner: Banner): BaseConfigBannerItem {
return {
id: banner.id ?? createBaseConfigItemId("banner"),
name: banner.banner_name ?? "",
imageId: banner.file_id ?? "",
isActive: banner.status !== "INACTIVE",
displayTimeSeconds: banner.display_time ?? 5,
sortOrder: banner.display_order ?? 1,
};
}
function mapConfigBannerToApi(banner: BaseConfigBannerItem): BannerMutate {
return {
banner_name: banner.name.trim(),
file_id: banner.imageId,
display_order: banner.sortOrder,
display_time: Math.max(1, banner.displayTimeSeconds || 1),
status: banner.isActive ? "ACTIVE" : "INACTIVE",
};
}
function mapSiteLogoToConfig(siteInformation: SiteInformationData): {
logo: BaseConfigLogoItem | null;
media: LogoMediaItem | null;
......@@ -493,6 +525,56 @@ export default function AdminBaseConfigPage() {
void loadSiteInformation();
const loadBanners = async () => {
try {
const response = await getBanner({
page: 1,
pageSize: 100,
sortField: "display_order",
sortOrder: "asc",
});
const pageData = getEnvelopeData<PageEnvelope<Banner>>(response);
const bannerRows = pageData?.rows ?? [];
const mediaRows = await Promise.all(
bannerRows
.map((banner) => banner.file_id)
.filter((fileId): fileId is string => Boolean(fileId))
.map(async (fileId) => {
const file = await fetchCmsFileById(fileId).catch(() => null);
return file ? toAdminMediaItem(file) : null;
}),
);
if (!mounted) return;
const nextBanners = bannerRows.map(mapApiBannerToConfig);
setMediaItems((previous) => {
const nextMap = new Map(previous.map((entry) => [entry.id, entry]));
mediaRows.forEach((item) => {
if (item) nextMap.set(item.id, item);
});
return Array.from(nextMap.values());
});
setConfig((previous) =>
previous
? {
...previous,
banners: nextBanners,
}
: previous,
);
setCurrentBannerIndex(0);
} catch (error) {
console.error(error);
if (mounted) {
toast.error("Không thể tải danh sách banner");
}
}
};
void loadBanners();
return () => {
mounted = false;
};
......@@ -609,7 +691,44 @@ export default function AdminBaseConfigPage() {
return;
}
const nextConfig = cloneBaseConfigData(config);
const bannerDraft: BaseConfigBannerItem = {
id: editingItemId || createBaseConfigItemId("banner"),
name: trimmedName,
imageId: itemForm.imageId,
isActive: itemForm.isActive,
displayTimeSeconds: itemForm.displayTimeSeconds,
sortOrder: itemForm.sortOrder,
};
try {
const response = editingItemId
? await putBannerId(editingItemId, mapConfigBannerToApi(bannerDraft))
: await postBanner(mapConfigBannerToApi(bannerDraft));
const savedBanner = getEnvelopeData<Banner>(response);
const nextBanner = savedBanner ? mapApiBannerToConfig(savedBanner) : bannerDraft;
const nextConfig = cloneBaseConfigData(config);
if (editingItemId) {
nextConfig.banners = nextConfig.banners.map((item) =>
item.id === editingItemId ? nextBanner : item,
);
} else {
nextConfig.banners.push(nextBanner);
setCurrentBannerIndex(Math.max(nextConfig.banners.length - 1, 0));
}
setConfig(nextConfig);
setSavingItem(false);
setItemDialogOpen(false);
toast.success("Đã lưu cấu hình banner");
} catch (error) {
console.error(error);
setSavingItem(false);
toast.error("Không thể lưu cấu hình banner");
}
return;
const nextConfig = cloneBaseConfigData(config!);
if (editingItemId) {
nextConfig.banners = nextConfig.banners.map((item) =>
......@@ -663,6 +782,7 @@ export default function AdminBaseConfigPage() {
return;
}
} else {
await deleteBannerId(deleteTarget.id);
nextConfig.banners = nextConfig.banners.filter((item) => item.id !== deleteTarget.id);
setCurrentBannerIndex((previous) =>
Math.max(0, Math.min(previous, nextConfig.banners.length - 1)),
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment