import { Component } from '@angular/core';
import { RouterLink } from '@angular/router';
import {
AUTH_FORGOT_PASSWORD_PATH,
COUNTRY_READ_PATH,
CURRENCY_CREATE_PATH,
CURRENCY_DELETE_PATH,
CURRENCY_READ_PATH,
CURRENCY_UPDATE_PATH,
DOCUMENT_READ_PATH,
FILE_READ_PATH,
MODE_CONFIG_PATH,
NOTIFICATION_READ_PATH,
NOTIFICATION_UPDATE_PATH,
PAYMENT_METHOD_READ_PATH,
PAYMENT_METHOD_UPDATE_PATH,
PLAN_READ_PATH,
PRODUCT_READ_PATH,
SERVICE_READ_PATH,
SHIPMENT_METHOD_READ_PATH,
USER_CHANGE_PASSWORD_PATH,
USER_LOGOUT_FROM_ALL_SESSIONS_PATH,
USER_PATH,
WAREHOUSE_READ_PATH,
ZONE_READ_PATH,
} from '@africanies/africanies-core';
import { DemoSectionComponent } from '../shared/demo-section.component';
import { PageHeaderComponent } from '../shared/page-header.component';
import { PlaygroundForgotPasswordComponent } from '../shared/playground-forgot-password.component';
import {
API_AUTH,
API_COUNTRY,
API_CURRENCY,
API_DOCUMENT,
API_FILE,
API_MODE_CONFIG,
API_NOTIFICATION,
API_OVERVIEW,
API_PAYMENT_METHOD,
API_PLAN,
API_PRODUCT,
API_SERVICE,
API_SHIPMENT_METHOD,
API_USER,
API_WAREHOUSE,
API_ZONE,
} from '../snippets';
interface ResourceIdRow {
id: string;
meaning: string;
path: string;
serviceCall: string;
customCall: string;
}
interface ApiServiceEntry {
id: string;
title: string;
hint: string;
path: string;
/** Models page fragment for the matching shape group. */
modelAnchor: string;
modelLabel: string;
resourceCalls?: {
page: string;
all: string;
byId: string;
};
returns?: string;
code: string;
}
interface ApiServiceGroup {
id: string;
title: string;
hint: string;
services: ApiServiceEntry[];
}
/**
* How-to catalog for `@africanies/africanies-core` HTTP services.
* Field shapes live on the Models page.
*/
@Component({
selector: 'app-api-page',
standalone: true,
imports: [
PageHeaderComponent,
DemoSectionComponent,
RouterLink,
PlaygroundForgotPasswordComponent,
],
template: `
After setup, inject a domain service below — or use ApiClient helpers for
custom routes.
| id |
Meaning |
Path |
Service |
Custom |
@for (row of resourceIdRows; track row.id) {
{{
row.id
}}
|
{{ row.meaning }}
|
{{ row.path }}
|
{{ row.serviceCall }}
|
{{ row.customCall }}
|
}
Paginated calls may send
page /
size /
order. Page size defaults to
15 when omitted (UI sizes:
5 /
15 /
30). Notifications default to
30.
Bind res.pagination to
africanies-pagination. Shapes:
Pagination & ResourceId.
@for (group of serviceGroups; track group.id) {
{{ group.title }}
{{ group.hint }}
@for (entry of group.services; track entry.id) {
-
Path
-
{{ entry.path }}
@if (entry.resourceCalls; as calls) {
-
Calls
-
{{ calls.page }}
{{ calls.all }}
{{ calls.byId }}
}
@if (entry.returns) {
-
Returns
-
{{ entry.returns }}
}
-
Model
-
{{ entry.modelLabel }}
@if (entry.id === 'auth') {
}
}
}
`,
})
export class ApiPage {
protected readonly overviewCode = API_OVERVIEW;
protected readonly resourceIdRows: ResourceIdRow[] = [
{
id: 'null',
meaning: 'Paginated page',
path: '{base}',
serviceCall: 'read() / readPage({ page })',
customCall: 'getResourcePage(base, query)',
},
{
id: "'all'",
meaning: 'Full list, not paginated',
path: '{base}/all',
serviceCall: "read('all') / readAll()",
customCall: 'getResourceAll(base)',
},
{
id: 'number',
meaning: 'Single matching record',
path: '{base}/{id}',
serviceCall: 'read(42) / readById(42)',
customCall: 'getResourceById(base, 42)',
},
];
protected readonly serviceGroups: ApiServiceGroup[] = [
{
id: 'reference-data',
title: 'Reference data',
hint: 'Catalog GETs that follow ResourceId — page, all, or by id.',
services: [
{
id: 'country',
title: 'CountryService',
hint: 'Public countries for destination pickers and address forms.',
path: `GET ${COUNTRY_READ_PATH}/{id?}`,
modelAnchor: 'country',
modelLabel: 'CountryModel',
resourceCalls: {
page: 'readPage({ page }) → CountryModel[]',
all: 'readAll() → CountryModel[]',
byId: 'readById(n) → CountryModel',
},
code: API_COUNTRY,
},
{
id: 'service',
title: 'ServiceService',
hint: 'Public App Settings subscription/add-on services. No auth required — same catalog the admin boards use for Services, Plans, and Plan Packages.',
path: `GET ${SERVICE_READ_PATH}/{id?}`,
modelAnchor: 'service',
modelLabel: 'ServiceModel',
resourceCalls: {
page: 'readPage({ page, order, search, from, to }) → ServiceModel[]',
all: 'readAll() → ServiceModel[]',
byId: 'readById(n) → ServiceModel',
},
code: API_SERVICE,
},
{
id: 'document',
title: 'DocumentService',
hint: 'Document catalog by numeric id — preview via readById → data.file_ref.base_64. For raw file_ref strings on records, use FileService.',
path: `GET ${DOCUMENT_READ_PATH}/{id?}`,
modelAnchor: 'document',
modelLabel: 'DocumentModel',
resourceCalls: {
page: 'readPage({ page, order, search, from, to }) → DocumentModel[]',
all: 'readAll() → DocumentModel[]',
byId: 'readById(n) → DocumentModel (file_ref preview)',
},
code: API_DOCUMENT,
},
{
id: 'plan',
title: 'PlanService',
hint: 'Public subscription plans with nested packages. Authenticated create/update/delete use api/plan/*.',
path: `GET ${PLAN_READ_PATH}/{id?}`,
modelAnchor: 'plan',
modelLabel: 'PlanModel',
resourceCalls: {
page: 'readPage({ page, order, search, from, to }) → PlanModel[]',
all: 'readAll() → PlanModel[]',
byId: 'readById(n) → PlanModel',
},
code: API_PLAN,
},
{
id: 'currency',
title: 'CurrencyService',
hint: 'App Settings currencies. PaymentMethodService.readPage() fills create/update checkboxes. Create name/code come from the host list, not GET. After each write, show res.message and readPage again.',
path: `GET ${CURRENCY_READ_PATH}/{id?} · POST ${CURRENCY_CREATE_PATH} · PUT ${CURRENCY_UPDATE_PATH} · DELETE ${CURRENCY_DELETE_PATH}`,
modelAnchor: 'currency',
modelLabel: 'CurrencyModel',
resourceCalls: {
page: 'readPage({ page, order, search, from, to }) → CurrencyModel[]',
all: 'readAll() → CurrencyModel[]',
byId: 'readById(n) → CurrencyModel',
},
returns:
'create(body) · update(body) · remove({ id }) → ApiResponseModel',
code: API_CURRENCY,
},
{
id: 'payment-method',
title: 'PaymentMethodService',
hint: 'App Settings payment methods. Read + active toggle only (no create/delete). After update, show res.message and patch that row’s updated_at — do not reload the list. Processors are linked from Currencies via payment_method_ids.',
path: `GET ${PAYMENT_METHOD_READ_PATH}/{id?} · PUT ${PAYMENT_METHOD_UPDATE_PATH}`,
modelAnchor: 'payment-method',
modelLabel: 'PaymentMethodModel',
resourceCalls: {
page: 'readPage({ page, order, search, from, to }) → PaymentMethodModel[]',
all: 'readAll() → PaymentMethodModel[]',
byId: 'readById(n) → PaymentMethodModel',
},
returns: 'update({ id, name, model, active }) → ApiResponseModel',
code: API_PAYMENT_METHOD,
},
{
id: 'shipment-method',
title: 'ShipmentMethodService',
hint: 'Carriers with delivery windows and zone values.',
path: `GET ${SHIPMENT_METHOD_READ_PATH}/{id?}`,
modelAnchor: 'shipment-method',
modelLabel: 'ShipmentMethodModel',
resourceCalls: {
page: 'readPage({ page }) → ShipmentMethodModel[]',
all: 'readAll() → ShipmentMethodModel[]',
byId: 'readById(n) → ShipmentMethodModel',
},
code: API_SHIPMENT_METHOD,
},
{
id: 'warehouse',
title: 'WarehouseService',
hint: 'Warehouse locations with address, charges, and nested country.',
path: `GET ${WAREHOUSE_READ_PATH}/{id?}`,
modelAnchor: 'warehouse',
modelLabel: 'WarehouseModel',
resourceCalls: {
page: 'readPage({ page }) → WarehouseModel[]',
all: 'readAll() → WarehouseModel[]',
byId: 'readById(n) → WarehouseModel',
},
code: API_WAREHOUSE,
},
{
id: 'zone',
title: 'ZoneService',
hint: 'Shipping zones for routing and pricing rules.',
path: `GET ${ZONE_READ_PATH}/{id?}`,
modelAnchor: 'zone',
modelLabel: 'ZoneModel',
resourceCalls: {
page: 'readPage({ page }) → ZoneModel[]',
all: 'readAll() → ZoneModel[]',
byId: 'readById(n) → ZoneModel',
},
code: API_ZONE,
},
{
id: 'product',
title: 'ProductService',
hint: 'Catalog products with HS codes and document / ETW labels.',
path: `GET ${PRODUCT_READ_PATH}/{id?}`,
modelAnchor: 'product',
modelLabel: 'ProductModel',
resourceCalls: {
page: 'readPage({ page }) → ProductModel[]',
all: 'readAll() → ProductModel[]',
byId: 'readById(n) → ProductModel',
},
code: API_PRODUCT,
},
],
},
{
id: 'session-config',
title: 'Session & config',
hint: 'Auth email flows, current user, and STN/SFN region units — not ResourceId list reads.',
services: [
{
id: 'auth',
title: 'AuthService',
hint: 'Email-only. POST { email } — backend emails a reset link. This UI never collects a new password for that link. Admins reuse forgot(email).',
path: `POST ${AUTH_FORGOT_PASSWORD_PATH}`,
modelAnchor: 'auth',
modelLabel: 'ForgotPasswordRequestModel',
returns: 'forgot(email) → ApiResponseModel',
code: API_AUTH,
},
{
id: 'user',
title: 'UserService',
hint: 'Current user. Call AuthTokenService.set(access_token) after login. If user.default_password, send them to /onboarding/reset-password (not the email-link flow). Logout: POST while the token is set, then AuthTokenService.clear().',
path: `GET ${USER_PATH} · POST ${USER_CHANGE_PASSWORD_PATH} · POST ${USER_LOGOUT_FROM_ALL_SESSIONS_PATH}`,
modelAnchor: 'user',
modelLabel: 'UserModel',
returns:
'me() → UserModel · changePassword(body) → ApiResponseModel · logoutFromAllSessions() → ApiResponseModel',
code: API_USER,
},
{
id: 'notification',
title: 'NotificationService',
hint: 'Authenticated inbox for the header bell — readPage for badge + drawer infinite scroll.',
path: `GET ${NOTIFICATION_READ_PATH}/{id?} · PUT ${NOTIFICATION_UPDATE_PATH}`,
modelAnchor: 'notification',
modelLabel: 'NotificationModel',
resourceCalls: {
page: 'readPage({ page }) → NotificationModel[]',
all: 'readAll() → NotificationModel[]',
byId: 'readOne(uuid) → NotificationModel',
},
returns: 'markRead(id?) → ApiResponseModel ({} marks all read)',
code: API_NOTIFICATION,
},
{
id: 'mode-config',
title: 'ModeConfigService',
hint: 'Region currency and units for STN/SFN — usually loaded at startup.',
path: `GET ${MODE_CONFIG_PATH}`,
modelAnchor: 'mode-config',
modelLabel: 'ModeConfigDataModel',
returns: 'loadConfig() → ModeConfigDataModel',
code: API_MODE_CONFIG,
},
],
},
{
id: 'files',
title: 'Files',
hint: 'Single-object file resolve — not a list, not paginated.',
services: [
{
id: 'file',
title: 'FileService',
hint: 'Primary preview when a record stores file_ref — POST { ref }. Waybills: readMultiple(ref) → POST ?multiple=yes.',
path: `POST ${FILE_READ_PATH} · POST ${FILE_READ_PATH}?multiple=yes`,
modelAnchor: 'file',
modelLabel: 'FileReadModel',
returns:
'read(ref) → FileReadModel · readMultiple(ref) → FileReadModel[]',
code: API_FILE,
},
],
},
];
}