diff --git a/README.md b/README.md index b3f5e9696..361b9afd8 100644 --- a/README.md +++ b/README.md @@ -37,8 +37,8 @@ emaui/ ``` ### libs/api -- `base-api/` — RTK Query `createApi` instance with `prepareHeaders` that injects the Bearer token from Redux state or localStorage. -- `session/` — `resolveTokenFromStorage()` reads from `localStorage` keys or `auth-token` cookie. `resolveSessionContext()` merges Redux state token with storage fallback. +- `base-api/` — RTK Query `createApi` instance with `prepareHeaders` that injects the Bearer token from Redux state or storage. +- `session/` — `resolveTokenFromStorage()` reads the `auth-token` cookie first, falling back to `localStorage` for legacy pre-migration sessions. `resolveSessionContext()` merges Redux state token with storage fallback. - `query-and-mutation/` — Generic `useApiQuery` / `useApiMutation` wrappers for one-off API calls without defining a dedicated endpoint file. ### libs/ui @@ -55,10 +55,10 @@ emaui/ 1. User submits the login form (LoginForm / LoginPage). 2. The form calls the `login` RTK Query mutation (backoffice) or a plain `fetch` (portal). -3. On success, `loginSuccess` action is dispatched → Redux `auth` slice stores `token` and `user`; `authStorage.setToken()` persists the token to `localStorage`. +3. On success, `loginSuccess` action is dispatched → Redux `auth` slice stores `token` and `user`; `authStorage.setToken()` persists the token to a cookie (both apps call `configureAuthStorage(prefix, true)`). 4. `baseApi`'s `prepareHeaders` reads the token via `resolveSessionContext(getState())` and attaches `Authorization: Bearer ` to every RTK Query request. -5. `ProtectedRoute` checks `localStorage` for the token key on every navigation — if absent, redirects to `/login`. -6. `logout` action clears Redux state and calls `authStorage.clear()` to remove all localStorage keys. +5. `ProtectedRoute` checks `authStorage`/the token cookie on every navigation — if absent, redirects to `/login`. +6. `logout` action clears Redux state and calls `authStorage.clear()` to remove all auth cookies. --- @@ -90,6 +90,8 @@ npm run dev:all |---|---|---|---| | `VITE_BASE_API_URL` | Yes | `http://localhost:3000` | Base URL for all API requests | | `VITE_ENABLE_DEVELOPER_TOOLS` | No | `true` | Toggle Redux DevTools | +| `VITE_PAYMENT_API_URL` | Yes (portal) | — | Base URL for the payment service (portal `payment` feature). Can be a same-origin path if a backend proxy is later placed in front of it | +| `VITE_PAYMENT_SERVICE_TOKEN` | Yes (portal) | — | Sent as `x-service-token` on every payment request. Note: bundled `VITE_*` values are public in the built app, not secret | | `PORTAL_PORT` | No | `4200` | Docker host port for portal | | `BACKOFFICE_PORT` | No | `4201` | Docker host port for backoffice | diff --git a/apps/backoffice/src/app/features/analytics/pages/api/analytics-api.ts b/apps/backoffice/src/app/features/analytics/pages/api/analytics-api.ts new file mode 100644 index 000000000..67f2a62fe --- /dev/null +++ b/apps/backoffice/src/app/features/analytics/pages/api/analytics-api.ts @@ -0,0 +1,2 @@ +// Analytics API - Coming soon +// test from claude diff --git a/apps/backoffice/src/app/features/analytics/pages/types/analytics.ts b/apps/backoffice/src/app/features/analytics/pages/types/analytics.ts new file mode 100644 index 000000000..ee0d73141 --- /dev/null +++ b/apps/backoffice/src/app/features/analytics/pages/types/analytics.ts @@ -0,0 +1 @@ +// Analytics types - Coming soon diff --git a/apps/backoffice/src/app/features/certificate-designer/pages/CertificateDesignerPage.tsx b/apps/backoffice/src/app/features/certificate-designer/pages/CertificateDesignerPage.tsx index 46b801648..9f47684df 100644 --- a/apps/backoffice/src/app/features/certificate-designer/pages/CertificateDesignerPage.tsx +++ b/apps/backoffice/src/app/features/certificate-designer/pages/CertificateDesignerPage.tsx @@ -39,12 +39,13 @@ import { useGetLicenseTemplatesQuery, useGetLicenseTypesQuery, useGetTemplateVariablesQuery, + useLocalized, usePublishLicenseTemplateMutation, useUpdateLicenseValidityMutation, useUpdateLicenseTemplateMutation, type LicenseTemplate, } from '@ema-platform/api'; -import { EmptyState, ErrorState, PageHeader } from '@ema-platform/ui'; +import { EmptyState, ErrorState, ModalFooter, PageHeader } from '@ema-platform/ui'; import { authStorage, usePermissions } from '@ema-platform/auth'; import { PERMISSIONS } from '../../../layouts/nav-config'; @@ -70,6 +71,7 @@ const STATUS_COLOR: Record = { */ export function CertificateDesignerPage() { const { t } = useTranslation(); + const localized = useLocalized(); const { can } = usePermissions(); const canEdit = can([PERMISSIONS.UPDATE_TEMPLATE]); @@ -226,7 +228,7 @@ export function CertificateDesignerPage() { label={t('designer.licenceType', 'Licence type')} data={(licenseTypes?.items ?? []).map((type) => ({ value: type.id, - label: type.name?.en ?? type.key, + label: localized(type.name) || type.key, }))} value={typeId} onChange={(value) => { @@ -529,7 +531,7 @@ export function CertificateDesignerPage() { 'Starts from the live design, or the built-in layout if this type has none.', )} - + @@ -550,7 +552,7 @@ export function CertificateDesignerPage() { > {t('designer.create', 'Create')} - + diff --git a/apps/backoffice/src/app/features/certification/pages/CertificationPage.tsx b/apps/backoffice/src/app/features/certification/pages/CertificationPage.tsx index d59296ad9..88fdbe449 100644 --- a/apps/backoffice/src/app/features/certification/pages/CertificationPage.tsx +++ b/apps/backoffice/src/app/features/certification/pages/CertificationPage.tsx @@ -4,22 +4,19 @@ import { Title, Group, Button, - Table, Badge, ActionIcon, Modal, Text, TextInput, Textarea, - Paper, - Loader, - Center, + Card, Alert, } from '@mantine/core'; import { useDisclosure } from '@mantine/hooks'; import { useTranslation } from 'react-i18next'; import { IconEdit, IconTrash, IconPlus, IconInfoCircle, IconCertificate } from '@tabler/icons-react'; -import { notify } from '@ema-platform/ui'; +import { notify, useErrorHandler, AdvancedTable, useServerTable, ModalFooter, type AdvancedColumn } from '@ema-platform/ui'; import { useGetCertificationsQuery, useCreateCertificationMutation, @@ -55,27 +52,29 @@ function CertificationForm({ }; return ( - +
setNameEn(e.currentTarget.value)} size="sm" required /> setNameAm(e.currentTarget.value)} size="sm" required />