Files
sam-react-prod/src/lib/api/master-data.ts

444 lines
10 KiB
TypeScript
Raw Normal View History

/**
* API
*
* Laravel API
* , ,
*/
import type {
PageConfig,
PageConfigRevision,
PageType,
DynamicFormData,
FetchPageConfigParams,
MasterDataApiResponse,
VersionComparisonResult,
} from '@/types/master-data';
// ===== 환경 변수 =====
const API_URL = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:8000';
// ===== 유틸리티 함수 =====
/**
*
*/
function getAuthToken(): string | null {
if (typeof window !== 'undefined') {
return localStorage.getItem('auth_token');
}
return null;
}
/**
* Fetch
*/
function createFetchOptions(options: RequestInit = {}): RequestInit {
const token = getAuthToken();
const headers: Record<string, string> = {
'Content-Type': 'application/json',
};
// Merge existing headers if they are a plain object
if (options.headers && typeof options.headers === 'object' && !Array.isArray(options.headers)) {
Object.assign(headers, options.headers);
}
if (token) {
headers['Authorization'] = `Bearer ${token}`;
}
return {
...options,
headers,
credentials: 'include',
};
}
/**
* API
*/
async function handleApiResponse<T>(response: Response): Promise<T> {
if (!response.ok) {
const error = await response.json().catch(() => ({
message: 'API 요청 실패',
}));
throw new Error(error.message || `HTTP ${response.status}: ${response.statusText}`);
}
const data = await response.json();
return data;
}
// ===== 페이지 구성 CRUD =====
/**
*
*
* @example
* const configs = await fetchPageConfigs({ pageType: 'item-master' });
*/
export async function fetchPageConfigs(
params?: FetchPageConfigParams
): Promise<PageConfig[]> {
const queryParams = new URLSearchParams();
if (params) {
Object.entries(params).forEach(([key, value]) => {
if (value !== undefined && value !== null) {
queryParams.append(key, String(value));
}
});
}
const url = `${API_URL}/api/master-data/pages${queryParams.toString() ? `?${queryParams}` : ''}`;
const response = await fetch(url, createFetchOptions());
const data = await handleApiResponse<MasterDataApiResponse<PageConfig[]>>(response);
return data.data;
}
/**
*
*
* @param pageType -
*
* @example
* const config = await fetchPageConfigByType('item-master');
*/
export async function fetchPageConfigByType(
pageType: PageType
): Promise<PageConfig | null> {
const response = await fetch(
`${API_URL}/api/master-data/pages/${pageType}`,
createFetchOptions()
);
if (response.status === 404) {
return null;
}
const data = await handleApiResponse<MasterDataApiResponse<PageConfig>>(response);
return data.data;
}
/**
* ( )
*
* @param id - ID
* @param version - (, 기본: 최신)
*
* @example
* const config = await fetchPageConfigById('uuid', 2);
*/
export async function fetchPageConfigById(
id: string,
version?: number
): Promise<PageConfig> {
const url = version
? `${API_URL}/api/master-data/pages/${id}?version=${version}`
: `${API_URL}/api/master-data/pages/${id}`;
const response = await fetch(url, createFetchOptions());
const data = await handleApiResponse<MasterDataApiResponse<PageConfig>>(response);
return data.data;
}
/**
*
*
* @param configData -
*
* @example
* const newConfig = await createPageConfig({
* pageName: '품목기준정보',
* pageType: 'item-master',
* sections: [...],
* isActive: true,
* });
*/
export async function createPageConfig(
configData: Omit<PageConfig, 'id' | 'version' | 'createdAt' | 'updatedAt' | 'tenantId'>
): Promise<PageConfig> {
const response = await fetch(
`${API_URL}/api/master-data/pages`,
createFetchOptions({
method: 'POST',
body: JSON.stringify(configData),
})
);
const data = await handleApiResponse<MasterDataApiResponse<PageConfig>>(response);
return data.data;
}
/**
*
*
* @param id - ID
* @param updates -
*
* @example
* const updatedConfig = await updatePageConfig('uuid', {
* sections: [...],
* });
*/
export async function updatePageConfig(
id: string,
updates: Partial<PageConfig>
): Promise<PageConfig> {
const response = await fetch(
`${API_URL}/api/master-data/pages/${id}`,
createFetchOptions({
method: 'PUT',
body: JSON.stringify(updates),
})
);
const data = await handleApiResponse<MasterDataApiResponse<PageConfig>>(response);
return data.data;
}
/**
*
*
* @param id - ID
*/
export async function deletePageConfig(id: string): Promise<void> {
const response = await fetch(
`${API_URL}/api/master-data/pages/${id}`,
createFetchOptions({
method: 'DELETE',
})
);
await handleApiResponse<MasterDataApiResponse<null>>(response);
}
// ===== 버전 관리 =====
/**
*
*
* @param pageConfigId - ID
*
* @example
* const revisions = await fetchPageConfigRevisions('uuid');
*/
export async function fetchPageConfigRevisions(
pageConfigId: string
): Promise<PageConfigRevision[]> {
const response = await fetch(
`${API_URL}/api/master-data/pages/${pageConfigId}/revisions`,
createFetchOptions()
);
const data = await handleApiResponse<MasterDataApiResponse<PageConfigRevision[]>>(response);
return data.data;
}
/**
*
*
* @param pageConfigId - ID
* @param version -
*/
export async function fetchPageConfigRevisionByVersion(
pageConfigId: string,
version: number
): Promise<PageConfigRevision> {
const response = await fetch(
`${API_URL}/api/master-data/pages/${pageConfigId}/revisions/${version}`,
createFetchOptions()
);
const data = await handleApiResponse<MasterDataApiResponse<PageConfigRevision>>(response);
return data.data;
}
/**
*
*
* @param pageConfigId - ID
* @param version1 - 1
* @param version2 - 2
*
* @example
* const comparison = await comparePageConfigVersions('uuid', 1, 2);
*/
export async function comparePageConfigVersions(
pageConfigId: string,
version1: number,
version2: number
): Promise<VersionComparisonResult> {
const response = await fetch(
`${API_URL}/api/master-data/pages/${pageConfigId}/compare?v1=${version1}&v2=${version2}`,
createFetchOptions()
);
const data = await handleApiResponse<MasterDataApiResponse<VersionComparisonResult>>(response);
return data.data;
}
/**
*
*
* @param revisionId - ID
*
* @example
* await approvePageConfigRevision('revision-uuid');
*/
export async function approvePageConfigRevision(
revisionId: string
): Promise<PageConfigRevision> {
const response = await fetch(
`${API_URL}/api/master-data/revisions/${revisionId}/approve`,
createFetchOptions({
method: 'POST',
})
);
const data = await handleApiResponse<MasterDataApiResponse<PageConfigRevision>>(response);
return data.data;
}
/**
*
*
* @param pageConfigId - ID
* @param version -
*/
export async function rollbackPageConfig(
pageConfigId: string,
version: number
): Promise<PageConfig> {
const response = await fetch(
`${API_URL}/api/master-data/pages/${pageConfigId}/rollback`,
createFetchOptions({
method: 'POST',
body: JSON.stringify({ version }),
})
);
const data = await handleApiResponse<MasterDataApiResponse<PageConfig>>(response);
return data.data;
}
// ===== 동적 폼 데이터 =====
/**
*
*
* @param pageType -
* @param id - ID ()
*/
export async function fetchFormData(
pageType: PageType,
id?: string
): Promise<DynamicFormData | DynamicFormData[]> {
const url = id
? `${API_URL}/api/master-data/form-data/${pageType}/${id}`
: `${API_URL}/api/master-data/form-data/${pageType}`;
const response = await fetch(url, createFetchOptions());
const data = await handleApiResponse<MasterDataApiResponse<DynamicFormData | DynamicFormData[]>>(response);
return data.data;
}
/**
*
*
* @param formData -
*/
export async function saveFormData(
formData: DynamicFormData
): Promise<DynamicFormData> {
const response = await fetch(
`${API_URL}/api/master-data/form-data`,
createFetchOptions({
method: 'POST',
body: JSON.stringify(formData),
})
);
const data = await handleApiResponse<MasterDataApiResponse<DynamicFormData>>(response);
return data.data;
}
/**
*
*
* @param id - ID
* @param updates -
*/
export async function updateFormData(
id: string,
updates: Partial<DynamicFormData>
): Promise<DynamicFormData> {
const response = await fetch(
`${API_URL}/api/master-data/form-data/${id}`,
createFetchOptions({
method: 'PUT',
body: JSON.stringify(updates),
})
);
const data = await handleApiResponse<MasterDataApiResponse<DynamicFormData>>(response);
return data.data;
}
/**
*
*
* @param id - ID
*/
export async function deleteFormData(id: string): Promise<void> {
const response = await fetch(
`${API_URL}/api/master-data/form-data/${id}`,
createFetchOptions({
method: 'DELETE',
})
);
await handleApiResponse<MasterDataApiResponse<null>>(response);
}
// ===== 캐싱 =====
/**
*
*
* @param pageType - (, )
*/
export async function invalidatePageConfigCache(
pageType?: PageType
): Promise<void> {
const url = pageType
? `${API_URL}/api/master-data/cache/invalidate/${pageType}`
: `${API_URL}/api/master-data/cache/invalidate`;
const response = await fetch(
url,
createFetchOptions({
method: 'POST',
})
);
await handleApiResponse<MasterDataApiResponse<null>>(response);
}
/**
* Next.js revalidation
*/
export async function revalidateMasterData(): Promise<void> {
if (typeof window === 'undefined') {
const { revalidatePath } = await import('next/cache');
revalidatePath('/master-data');
}
}