refactor: remove single-page module and related components
This commit is contained in:
@@ -2,13 +2,13 @@ import { lazy } from 'react';
|
|||||||
import { Routes, Route, Navigate } from 'react-router-dom';
|
import { Routes, Route, Navigate } from 'react-router-dom';
|
||||||
|
|
||||||
const FullPageModule = lazy(() => import('./full-page/presentation/factory'));
|
const FullPageModule = lazy(() => import('./full-page/presentation/factory'));
|
||||||
const SinglePageModule = lazy(() => import('./single-page/presentation/factory'));
|
// const SinglePageModule = lazy(() => import('./single-page/presentation/factory'));
|
||||||
|
|
||||||
export default function ExampleModule() {
|
export default function ExampleModule() {
|
||||||
return (
|
return (
|
||||||
<Routes>
|
<Routes>
|
||||||
<Route path="/full-page/*" element={<FullPageModule />} />
|
<Route path="/full-page/*" element={<FullPageModule />} />
|
||||||
<Route path="/single-page/*" element={<SinglePageModule />} />
|
{/* <Route path="/single-page/*" element={<SinglePageModule />} /> */}
|
||||||
<Route path="*" element={<Navigate to={'/404'} replace={true} />} />
|
<Route path="*" element={<Navigate to={'/404'} replace={true} />} />
|
||||||
</Routes>
|
</Routes>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,25 +0,0 @@
|
|||||||
import { BaseRemoteDataServices } from '@repo/core-api/data-services';
|
|
||||||
import { SinglePageDTO, SinglePageEntity } from '../domain/entities';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Full Page Remote Data Services
|
|
||||||
*
|
|
||||||
* Provides core data services for the single-page module by extending the base remote data services.
|
|
||||||
* While this class automatically handles standard CRUD operations and data transformations out-of-the-box,
|
|
||||||
* implementers can freely extend it by adding custom methods to support domain-specific API endpoints
|
|
||||||
* or complex business logic as needed.
|
|
||||||
*
|
|
||||||
* @example
|
|
||||||
* ```ts
|
|
||||||
* export class SinglePageRemoteDataServices extends BaseRemoteDataServices<SinglePageEntity, SinglePageDTO> {
|
|
||||||
* // Example of adding a custom method tailored to specific module needs
|
|
||||||
* public async getDashboardMetrics(status: string): Promise<MetricsPayload> {
|
|
||||||
* const response = await this.httpClient.get(`${this.apiUrl}/metrics`, {
|
|
||||||
* params: { status }
|
|
||||||
* });
|
|
||||||
* return response.data;
|
|
||||||
* }
|
|
||||||
* }
|
|
||||||
* ```
|
|
||||||
*/
|
|
||||||
export class SinglePageRemoteDataServices extends BaseRemoteDataServices<SinglePageEntity, SinglePageDTO> {}
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
export * from './single-page.constants';
|
|
||||||
-25
@@ -1,25 +0,0 @@
|
|||||||
import { ModuleConfigEntity } from '@repo/ui/foundations';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Core configuration and constants for the Full Page module.
|
|
||||||
* Used across Domain, Data, and Presentation layers.
|
|
||||||
*/
|
|
||||||
export const singlePageModuleConfig: ModuleConfigEntity = {
|
|
||||||
/** Unique identifier for permissions, caching, and i18n */
|
|
||||||
moduleKey: 'EXAMPLE_SINGLE_PAGE',
|
|
||||||
|
|
||||||
/** Translation namespace — must match the namespace used in registerModuleNamespace() */
|
|
||||||
translationNamespace: 'single-page',
|
|
||||||
|
|
||||||
/** Base API endpoint for remote data services */
|
|
||||||
apiUrl: '/single-page',
|
|
||||||
|
|
||||||
/** Base Web Router URL for UI navigation */
|
|
||||||
webUrl: '/app/example/single-page',
|
|
||||||
|
|
||||||
/** Architectural category of the module, used for rendering and routing logic */
|
|
||||||
moduleCategory: 'SINGLE_PAGE',
|
|
||||||
|
|
||||||
/** */
|
|
||||||
moduleType: 'MASTER_DATA',
|
|
||||||
} as const;
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
export * from './single-page.entity';
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
import { BaseEntity } from '@repo/core-api/data-services';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Represents a single-page entity in the frontend domain model.
|
|
||||||
*
|
|
||||||
* This entity is derived from the API's `SinglePageDTO` via the
|
|
||||||
* {@link SinglePageTransformer}, which handles field name mapping
|
|
||||||
* and computed field derivation.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
export interface SinglePageEntity extends BaseEntity {
|
|
||||||
status?: string;
|
|
||||||
name?: string;
|
|
||||||
code?: string;
|
|
||||||
description?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Represents the raw data structure returned by the API for a single-page resource.
|
|
||||||
*
|
|
||||||
* This DTO uses snake_case field names matching the backend's JSON serialization.
|
|
||||||
* It is transformed into a {@link SinglePageEntity} by the {@link SinglePageTransformer}.
|
|
||||||
*/
|
|
||||||
export interface SinglePageDTO extends SinglePageEntity {
|
|
||||||
[key: string]: any;
|
|
||||||
}
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
/**
|
|
||||||
* Full Page Factory
|
|
||||||
*
|
|
||||||
* This module acts as the dependency injection and configuration center for the single-page feature.
|
|
||||||
* It pre-configures and exports singleton instances of the data transformer and data service.
|
|
||||||
* By centralizing the instantiation here, it ensures that all UI components and hooks
|
|
||||||
* within the module share the same API client, configuration, and transformation logic.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { apiClient } from '../../../../../../core/lib/api-client';
|
|
||||||
import { SinglePageRemoteDataServices } from '../../data/single-page.remote.service';
|
|
||||||
import { singlePageModuleConfig } from '../constants/single-page.constants';
|
|
||||||
import { SinglePageRemoteDataTransformer } from '../transformers/single-page.remote.transformer';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Singleton instance of the SinglePageRemoteDataTransformer.
|
|
||||||
* Exported for potential direct usage if manual data mapping is required outside the standard API flow.
|
|
||||||
*/
|
|
||||||
export const singlePageDataTransformer = new SinglePageRemoteDataTransformer();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Pre-configured singleton instance of the SinglePageRemoteDataServices.
|
|
||||||
* Ready to be consumed by UI components, state managers, or module providers.
|
|
||||||
* It is fully wired with the HTTP client and automatically handles data mapping via the injected transformer.
|
|
||||||
*/
|
|
||||||
export const singlePageDataService = new SinglePageRemoteDataServices(apiClient, {
|
|
||||||
apiUrl: singlePageModuleConfig.apiUrl,
|
|
||||||
moduleKey: singlePageModuleConfig.moduleKey,
|
|
||||||
transformer: singlePageDataTransformer,
|
|
||||||
});
|
|
||||||
-45
@@ -1,45 +0,0 @@
|
|||||||
import { BaseDataTransformer } from '@repo/core-api/data-services';
|
|
||||||
import { SinglePageEntity, SinglePageDTO } from '../entities';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Full Page Remote Data Transformer
|
|
||||||
*
|
|
||||||
* Responsible for transforming data between the raw API data transfer objects (DTOs)
|
|
||||||
* and the frontend domain entities for the single-page module. By extending the base transformer,
|
|
||||||
* it ensures strict type safety and decouples data parsing logic from the API service layer.
|
|
||||||
*
|
|
||||||
* Implementers must define the core mapping rules (`transformToEntity`, `transformToDTO`)
|
|
||||||
* and can freely add custom transformation methods for specific API responses.
|
|
||||||
*
|
|
||||||
* @example
|
|
||||||
* ```ts
|
|
||||||
* export class SinglePageRemoteDataTransformer extends BaseDataTransformer<SinglePageEntity, SinglePageDTO> {
|
|
||||||
* // Map snake_case API payload to camelCase frontend entity
|
|
||||||
* public transformToEntity(dto: SinglePageDTO): SinglePageEntity {
|
|
||||||
* return {
|
|
||||||
* id: dto.id,
|
|
||||||
* documentNumber: dto.document_number,
|
|
||||||
* createdAt: new Date(dto.created_at),
|
|
||||||
* // ... other property mappings
|
|
||||||
* };
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
* // Map camelCase frontend entity back to snake_case API payload
|
|
||||||
* public transformToDTO(entity: SinglePageEntity): SinglePageDTO {
|
|
||||||
* return {
|
|
||||||
* id: entity.id,
|
|
||||||
* document_number: entity.documentNumber,
|
|
||||||
* // ... other property mappings
|
|
||||||
* };
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
* // Example of adding a custom transformation method for a specific feature
|
|
||||||
* public transformMetrics(rawData: any): MetricsEntity {
|
|
||||||
* return {
|
|
||||||
* totalActive: rawData.total_active_count ?? 0,
|
|
||||||
* };
|
|
||||||
* }
|
|
||||||
* }
|
|
||||||
* ```
|
|
||||||
*/
|
|
||||||
export class SinglePageRemoteDataTransformer extends BaseDataTransformer<SinglePageEntity, SinglePageDTO> {}
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
import { lazy } from 'react';
|
|
||||||
import { Navigate, Route, Routes } from 'react-router-dom';
|
|
||||||
import { EnterpriseModuleProvider } from '@repo/ui/foundations';
|
|
||||||
import { registerModuleNamespace } from '@repo/core-i18n';
|
|
||||||
import { singlePageModuleConfig } from '../../domain/constants';
|
|
||||||
import { singlePageDataService } from '../../domain/factories';
|
|
||||||
import { SinglePageEntity } from '../../domain/entities';
|
|
||||||
import { singlePageStore } from '../store';
|
|
||||||
|
|
||||||
import singlePageId from '../languages/id/single-page.json';
|
|
||||||
import singlePageEn from '../languages/en/single-page.json';
|
|
||||||
|
|
||||||
const IndexPage = lazy(() => import('../pages/single-page.page.index'));
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
|
||||||
// Namespace Registration (Module Scope)
|
|
||||||
// ---------------------------------------------------------------------------
|
|
||||||
// Called once at import time — safe, idempotent, outside React render cycle.
|
|
||||||
// The namespace 'single-page' must match config.translationNamespace.
|
|
||||||
registerModuleNamespace(singlePageModuleConfig.translationNamespace, {
|
|
||||||
id: singlePageId,
|
|
||||||
en: singlePageEn,
|
|
||||||
});
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
|
||||||
// Module Factory
|
|
||||||
// ---------------------------------------------------------------------------
|
|
||||||
export default function SinglePageModule() {
|
|
||||||
return (
|
|
||||||
<EnterpriseModuleProvider<SinglePageEntity>
|
|
||||||
config={singlePageModuleConfig}
|
|
||||||
dataServices={singlePageDataService}
|
|
||||||
store={singlePageStore}
|
|
||||||
>
|
|
||||||
<Routes>
|
|
||||||
<Route path="/index" element={<IndexPage />} />
|
|
||||||
<Route path="/" element={<Navigate to={`${singlePageModuleConfig.webUrl}/index`} replace={true} />} />
|
|
||||||
<Route path="*" element={<Navigate to={'/404'} replace={true} />} />
|
|
||||||
</Routes>
|
|
||||||
</EnterpriseModuleProvider>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
-9
@@ -1,9 +0,0 @@
|
|||||||
{
|
|
||||||
"title": "Single Page Management",
|
|
||||||
"fields": {
|
|
||||||
"status": "Status",
|
|
||||||
"name": "Name",
|
|
||||||
"code": "Code",
|
|
||||||
"description": "Description"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
-9
@@ -1,9 +0,0 @@
|
|||||||
{
|
|
||||||
"title": "Manajemen Halaman Tunggal",
|
|
||||||
"fields": {
|
|
||||||
"status": "Status",
|
|
||||||
"name": "Nama",
|
|
||||||
"code": "Kode",
|
|
||||||
"description": "Deskripsi"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
-99
@@ -1,99 +0,0 @@
|
|||||||
import { Table, Box, Title, Paper } from '@repo/ui/components';
|
|
||||||
import { PageActions } from '@repo/ui/components';
|
|
||||||
import { useEnterpriseModuleTranslationContext, useEnterpriseModuleNavigationContext } from '@repo/ui/foundations';
|
|
||||||
import { SinglePageEntity } from '../../domain/entities';
|
|
||||||
import { Edit2, Eye, Copy, Trash2 } from 'lucide-react';
|
|
||||||
import { useCallback } from 'react';
|
|
||||||
|
|
||||||
// TODO: Replace this mock data with real API data loaded from DataService via useEnterpriseModuleDataServiceContext
|
|
||||||
const MOCK_DATA: SinglePageEntity[] = [
|
|
||||||
{ id: '1', name: 'Dashboard Widget', code: 'WID-001', status: 'ACTIVE', description: 'Main dashboard widget' },
|
|
||||||
{ id: '2', name: 'Report Generator', code: 'REP-002', status: 'INACTIVE', description: 'Generates monthly reports' },
|
|
||||||
{
|
|
||||||
id: '3',
|
|
||||||
name: 'User Management',
|
|
||||||
code: 'USR-003',
|
|
||||||
status: 'ACTIVE',
|
|
||||||
description: 'Manages user roles and permissions',
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
export default function SinglePagePageIndex() {
|
|
||||||
// Translation is scoped to ['SINGLE_PAGE', 'common'] — no prefix needed for module keys
|
|
||||||
const { t } = useEnterpriseModuleTranslationContext();
|
|
||||||
|
|
||||||
const { navigateToDetail, navigateToEdit, navigateToDuplicate } = useEnterpriseModuleNavigationContext();
|
|
||||||
|
|
||||||
const getRowActions = useCallback(
|
|
||||||
(row: SinglePageEntity) => [
|
|
||||||
{
|
|
||||||
key: 'view',
|
|
||||||
label: t('common:view'),
|
|
||||||
icon: <Eye size={14} />,
|
|
||||||
onClick: () => navigateToDetail(row.id as string),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'edit',
|
|
||||||
label: t('common:edit'),
|
|
||||||
icon: <Edit2 size={14} />,
|
|
||||||
onClick: () => navigateToEdit(row.id as string),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'duplicate',
|
|
||||||
label: t('common:duplicate'),
|
|
||||||
icon: <Copy size={14} />,
|
|
||||||
onClick: () => navigateToDuplicate(row.id as string),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: 'divider' as const,
|
|
||||||
key: 'div-1',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'delete',
|
|
||||||
label: t('common:delete'),
|
|
||||||
icon: <Trash2 size={14} />,
|
|
||||||
intent: 'destructive' as const,
|
|
||||||
onClick: () => {
|
|
||||||
// Mock delete action
|
|
||||||
alert(`Delete ${row.name}`);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
[t, navigateToDetail, navigateToEdit, navigateToDuplicate],
|
|
||||||
);
|
|
||||||
|
|
||||||
const rows = MOCK_DATA.map((item) => (
|
|
||||||
<Table.Tr key={item.id}>
|
|
||||||
<Table.Td>{item.code}</Table.Td>
|
|
||||||
<Table.Td>{item.name}</Table.Td>
|
|
||||||
<Table.Td>{item.status}</Table.Td>
|
|
||||||
<Table.Td>{item.description}</Table.Td>
|
|
||||||
<Table.Td>
|
|
||||||
<PageActions actions={getRowActions(item)} />
|
|
||||||
</Table.Td>
|
|
||||||
</Table.Tr>
|
|
||||||
));
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Box p="md">
|
|
||||||
<Title order={2} mb="md">
|
|
||||||
{t('title')}
|
|
||||||
</Title>
|
|
||||||
|
|
||||||
<Paper withBorder shadow="sm" radius="md">
|
|
||||||
<Table striped highlightOnHover>
|
|
||||||
<Table.Thead>
|
|
||||||
<Table.Tr>
|
|
||||||
<Table.Th>{t('fields.code')}</Table.Th>
|
|
||||||
<Table.Th>{t('fields.name')}</Table.Th>
|
|
||||||
<Table.Th>{t('fields.status')}</Table.Th>
|
|
||||||
<Table.Th>{t('fields.description')}</Table.Th>
|
|
||||||
<Table.Th w={200}>{t('common:edit')}</Table.Th>
|
|
||||||
</Table.Tr>
|
|
||||||
</Table.Thead>
|
|
||||||
<Table.Tbody>{rows}</Table.Tbody>
|
|
||||||
</Table>
|
|
||||||
</Paper>
|
|
||||||
</Box>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
import { create } from 'zustand';
|
|
||||||
import { EnterpriseModuleState } from '@repo/ui/foundations';
|
|
||||||
import { SinglePageEntity } from '../../domain/entities';
|
|
||||||
|
|
||||||
export interface SinglePageStoreState extends EnterpriseModuleState<SinglePageEntity> {}
|
|
||||||
|
|
||||||
export const singlePageStore = create<SinglePageStoreState>((set) => ({
|
|
||||||
metaData: null,
|
|
||||||
setMetaData: (data) => set({ metaData: data }),
|
|
||||||
|
|
||||||
filterData: { page: 1, limit: 10 },
|
|
||||||
setFilterData: (data) => set({ filterData: data }),
|
|
||||||
|
|
||||||
selectedRows: [],
|
|
||||||
setSelectedRows: (rows) => set({ selectedRows: rows }),
|
|
||||||
|
|
||||||
privileges: [],
|
|
||||||
setPrivileges: (privileges) => set({ privileges }),
|
|
||||||
}));
|
|
||||||
@@ -247,12 +247,12 @@ export const MENU_ITEMS: MenuItemType[] = [
|
|||||||
icon: LayoutDashboard,
|
icon: LayoutDashboard,
|
||||||
path: '/app/example/full-page/index',
|
path: '/app/example/full-page/index',
|
||||||
},
|
},
|
||||||
{
|
// {
|
||||||
key: 'example-single-page',
|
// key: 'example-single-page',
|
||||||
label: 'nav:example-single-page',
|
// label: 'nav:example-single-page',
|
||||||
icon: FileText,
|
// icon: FileText,
|
||||||
path: '/app/example/single-page/index',
|
// path: '/app/example/single-page/index',
|
||||||
},
|
// },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|||||||
Reference in New Issue
Block a user