From 22d097367b423a403e6883febe57ca8290b538c7 Mon Sep 17 00:00:00 2001 From: joshuakrueger-dfx Date: Tue, 25 Aug 2026 16:27:40 +0200 Subject: [PATCH 1/5] feat(support): send clerkUserDataId instead of clerk name Assign support tickets by staff userData id so a renamed clerk no longer splits history. --- src/__tests__/realunit-dashboard.hook.test.ts | 8 +++--- .../staff-verified-name.hook.test.ts | 25 ++++++++--------- src/hooks/realunit-support.hook.ts | 15 ++++++----- src/hooks/staff-verified-name.hook.ts | 2 +- src/hooks/support-dashboard.hook.ts | 21 ++++++++++----- src/screens/realunit-support-issue.screen.tsx | 27 ++++++++++++------- .../support-dashboard-issue.screen.tsx | 21 +++++++++------ 7 files changed, 71 insertions(+), 48 deletions(-) diff --git a/src/__tests__/realunit-dashboard.hook.test.ts b/src/__tests__/realunit-dashboard.hook.test.ts index fbfcb8f23..df681aba1 100644 --- a/src/__tests__/realunit-dashboard.hook.test.ts +++ b/src/__tests__/realunit-dashboard.hook.test.ts @@ -60,11 +60,11 @@ describe('useRealunitSupport', () => { await result.current.getIssueData(42); expect(mockCall).toHaveBeenCalledWith({ url: 'realunit/support/42/data', method: 'GET' }); - await result.current.updateIssue(42, { state: 'Completed', clerk: 'Alice' }); + await result.current.updateIssue(42, { state: 'Completed', clerkUserDataId: 9 }); expect(mockCall).toHaveBeenCalledWith({ url: 'realunit/support/42', method: 'PUT', - data: { state: 'Completed', clerk: 'Alice' }, + data: { state: 'Completed', clerkUserDataId: 9 }, }); await result.current.createMessage(42, { author: 'Alice', message: 'hi' }); @@ -89,13 +89,13 @@ describe('useRealunitSupport', () => { }); it('getMyClerk GETs realunit/support/clerk and trims the clerk name', async () => { - mockCall.mockResolvedValue({ clerk: ' Ada ' }); + mockCall.mockResolvedValue({ clerkUserDataId: 7, clerk: ' Ada ' }); const { result } = renderHook(() => useRealunitSupport()); const clerk = await result.current.getMyClerk(); expect(mockCall).toHaveBeenCalledWith({ url: 'realunit/support/clerk', method: 'GET' }); - expect(clerk).toBe('Ada'); + expect(clerk).toEqual({ clerkUserDataId: 7, clerk: 'Ada' }); }); it('getMyClerk returns undefined when clerk is null or blank', async () => { diff --git a/src/__tests__/staff-verified-name.hook.test.ts b/src/__tests__/staff-verified-name.hook.test.ts index 65afd865f..d6cae3d89 100644 --- a/src/__tests__/staff-verified-name.hook.test.ts +++ b/src/__tests__/staff-verified-name.hook.test.ts @@ -40,7 +40,7 @@ describe('useStaffVerifiedName', () => { }); it('loads the trimmed clerk name from the support endpoint', async () => { - mockGetSupportClerk.mockResolvedValue(' Ada Lovelace '); + mockGetSupportClerk.mockResolvedValue({ clerkUserDataId: 42, clerk: ' Ada Lovelace ' }); const { result } = renderHook(() => useStaffVerifiedName()); @@ -58,7 +58,7 @@ describe('useStaffVerifiedName', () => { it('uses the RealUnit clerk endpoint and does not call getUserData when clerk is present', async () => { mockAuth.session = { account: 42, role: 'RealUnit' }; - mockGetRealunitClerk.mockResolvedValue('Real Unit Clerk'); + mockGetRealunitClerk.mockResolvedValue({ clerkUserDataId: 42, clerk: 'Real Unit Clerk' }); const { result } = renderHook(() => useStaffVerifiedName()); @@ -85,7 +85,7 @@ describe('useStaffVerifiedName', () => { }); it('falls back to getUserData when clerk is blank', async () => { - mockGetSupportClerk.mockResolvedValue(' '); + mockGetSupportClerk.mockResolvedValue({ clerkUserDataId: 42, clerk: ' ' }); mockGetUserData.mockResolvedValue({ userData: { verifiedName: 'Ada Lovelace' } }); const { result } = renderHook(() => useStaffVerifiedName()); @@ -181,8 +181,8 @@ describe('useStaffVerifiedName', () => { }); it('reloads from the RealUnit endpoint when the same account changes role', async () => { - mockGetSupportClerk.mockResolvedValue('Ada Lovelace'); - mockGetRealunitClerk.mockResolvedValue('Real Unit Clerk'); + mockGetSupportClerk.mockResolvedValue({ clerkUserDataId: 42, clerk: 'Ada Lovelace' }); + mockGetRealunitClerk.mockResolvedValue({ clerkUserDataId: 42, clerk: 'Real Unit Clerk' }); const { result, rerender } = renderHook(() => useStaffVerifiedName()); await waitFor(() => expect(result.current.name).toBe('Ada Lovelace')); @@ -201,8 +201,8 @@ describe('useStaffVerifiedName', () => { }); it('reuses the in-flight request for the same account', async () => { - let resolveRequest!: (value: string | undefined) => void; - const request = new Promise((resolve) => { + let resolveRequest!: (value: { clerkUserDataId: number; clerk: string } | undefined) => void; + const request = new Promise<{ clerkUserDataId: number; clerk: string } | undefined>((resolve) => { resolveRequest = resolve; }); mockGetSupportClerk.mockReturnValue(request); @@ -213,7 +213,7 @@ describe('useStaffVerifiedName', () => { expect(mockGetSupportClerk).toHaveBeenCalledTimes(1); await act(async () => { - resolveRequest('Ada Lovelace'); + resolveRequest({ clerkUserDataId: 42, clerk: 'Ada Lovelace' }); await request; }); @@ -224,7 +224,8 @@ describe('useStaffVerifiedName', () => { it('does not keep the previous name while another account is loading', async () => { mockGetSupportClerk.mockImplementation(() => { const account = mockAuth.session?.account; - return Promise.resolve(account === 42 ? 'Ada Lovelace' : 'Grace Hopper'); + const clerk = account === 42 ? 'Ada Lovelace' : 'Grace Hopper'; + return Promise.resolve({ clerkUserDataId: account ?? 0, clerk }); }); const { result, rerender } = renderHook(() => useStaffVerifiedName()); @@ -241,8 +242,8 @@ describe('useStaffVerifiedName', () => { }); it('ignores a resolved request after unmounting', async () => { - let resolveRequest!: (value: string | undefined) => void; - const request = new Promise((resolve) => { + let resolveRequest!: (value: { clerkUserDataId: number; clerk: string } | undefined) => void; + const request = new Promise<{ clerkUserDataId: number; clerk: string } | undefined>((resolve) => { resolveRequest = resolve; }); mockGetSupportClerk.mockReturnValue(request); @@ -251,7 +252,7 @@ describe('useStaffVerifiedName', () => { unmount(); await act(async () => { - resolveRequest('Ada Lovelace'); + resolveRequest({ clerkUserDataId: 42, clerk: 'Ada Lovelace' }); await Promise.resolve(); }); }); diff --git a/src/hooks/realunit-support.hook.ts b/src/hooks/realunit-support.hook.ts index 0a271b3e5..f3a32ae7b 100644 --- a/src/hooks/realunit-support.hook.ts +++ b/src/hooks/realunit-support.hook.ts @@ -1,6 +1,7 @@ import { useMemo } from 'react'; import { useGuardedApi } from './guarded-api.hook'; import { + SupportClerk, SupportIssueInternalData, SupportIssueListItem, SupportMessageInfo, @@ -46,20 +47,20 @@ export function useRealunitSupport() { }); } - async function getClerks(): Promise { - return call({ + async function getClerks(): Promise { + return call({ url: 'realunit/support/clerks', method: 'GET', }); } - // the clerk name mapped to the logged-in RealUnit support account (null if unmapped) - async function getMyClerk(): Promise { - const result = await call<{ clerk: string | null }>({ + async function getMyClerk(): Promise<{ clerkUserDataId: number; clerk: string } | undefined> { + const result = await call<{ clerkUserDataId: number; clerk: string }>({ url: 'realunit/support/clerk', method: 'GET', }); - return result.clerk?.trim() || undefined; + const clerk = result.clerk?.trim(); + return clerk ? { clerkUserDataId: result.clerkUserDataId, clerk } : undefined; } async function getIssueData(issueId: number): Promise { @@ -71,7 +72,7 @@ export function useRealunitSupport() { async function updateIssue( issueId: number, - data: { state?: string; clerk?: string; department?: string }, + data: { state?: string; clerkUserDataId?: number | null; department?: string }, ): Promise { return call({ url: `realunit/support/${issueId}`, diff --git a/src/hooks/staff-verified-name.hook.ts b/src/hooks/staff-verified-name.hook.ts index 5387d4a5c..b44d2afd3 100644 --- a/src/hooks/staff-verified-name.hook.ts +++ b/src/hooks/staff-verified-name.hook.ts @@ -41,7 +41,7 @@ export function useStaffVerifiedName(): { name?: string; isLoading: boolean; err if (!pending) { const loadClerk = role === UserRole.REALUNIT ? getRealunitClerk : getSupportClerk; pending = loadClerk() - .then((clerk) => readVerifiedName(clerk)) + .then((result) => readVerifiedName(result?.clerk)) // 404/403 while the companion API clerk route is not deployed yet: fall through to userData. .catch(() => undefined) .then((fromClerk) => { diff --git a/src/hooks/support-dashboard.hook.ts b/src/hooks/support-dashboard.hook.ts index ad653b210..540d3c76e 100644 --- a/src/hooks/support-dashboard.hook.ts +++ b/src/hooks/support-dashboard.hook.ts @@ -15,6 +15,7 @@ export interface SupportIssueListItem { state: string; name: string; clerk?: string; + clerkUserDataId?: number; department?: string; created: string; updated?: string; @@ -79,6 +80,7 @@ export interface SupportIssueInternalData { state: string; name: string; clerk?: string; + clerkUserDataId?: number; account: SupportIssueInternalAccountData; transaction?: SupportIssueInternalTransactionData; limitRequest?: SupportIssueInternalLimitRequestData; @@ -123,6 +125,11 @@ export interface SupportStatisticsDto { resolutionByType: SupportResolutionBucket[]; } +export interface SupportClerk { + userDataId: number; + name: string; +} + export function useSupportDashboard() { // staff endpoints answer with HTTP 403 { code: 'TFA_REQUIRED' } when the session still needs 2FA; // useGuardedApi routes that into the bearer-based 2FA flow instead of surfacing a raw error @@ -169,20 +176,20 @@ export function useSupportDashboard() { }); } - async function getClerks(): Promise { - return guardedCall({ + async function getClerks(): Promise { + return guardedCall({ url: 'support/issue/clerks', method: 'GET', }); } - // the clerk name mapped to the logged-in support account (null if unmapped) - async function getMyClerk(): Promise { - const result = await guardedCall<{ clerk: string | null }>({ + async function getMyClerk(): Promise<{ clerkUserDataId: number; clerk: string } | undefined> { + const result = await guardedCall<{ clerkUserDataId: number; clerk: string }>({ url: 'support/issue/clerk', method: 'GET', }); - return result.clerk?.trim() || undefined; + const clerk = result.clerk?.trim(); + return clerk ? { clerkUserDataId: result.clerkUserDataId, clerk } : undefined; } async function getIssueData(issueId: number): Promise { @@ -194,7 +201,7 @@ export function useSupportDashboard() { async function updateIssue( issueId: number, - data: { state?: string; clerk?: string; department?: string }, + data: { state?: string; clerkUserDataId?: number | null; department?: string }, ): Promise { return guardedCall({ url: `support/issue/${issueId}`, diff --git a/src/screens/realunit-support-issue.screen.tsx b/src/screens/realunit-support-issue.screen.tsx index 2cad942c8..b8bdba7e6 100644 --- a/src/screens/realunit-support-issue.screen.tsx +++ b/src/screens/realunit-support-issue.screen.tsx @@ -13,7 +13,12 @@ import { useRealunitSupport } from 'src/hooks/realunit-support.hook'; import { STAFF_NAME_MISSING, staffNameLoadError } from 'src/components/compliance/staff-identity'; import { useStaffVerifiedName } from 'src/hooks/staff-verified-name.hook'; import { useSplitPane } from 'src/hooks/split-pane.hook'; -import { ASSIGNABLE_DEPARTMENTS, SupportIssueInternalData, SupportMessageInfo } from 'src/hooks/support-dashboard.hook'; +import { + ASSIGNABLE_DEPARTMENTS, + SupportClerk, + SupportIssueInternalData, + SupportMessageInfo, +} from 'src/hooks/support-dashboard.hook'; import { formatDateTime, statusBadge } from 'src/util/compliance-helpers'; import { reasonLabel, typeLabel } from 'src/util/support-helpers'; import { toBase64 } from 'src/util/utils'; @@ -33,7 +38,7 @@ export default function RealunitSupportIssueScreen(): JSX.Element { const [messages, setMessages] = useState([]); const [pendingCount, setPendingCount] = useState(0); const visibleIdsRef = useRef>(new Set()); - const [clerks, setClerks] = useState([]); + const [clerks, setClerks] = useState([]); // Update form state const [updateState, setUpdateState] = useState(''); @@ -76,7 +81,7 @@ export default function RealunitSupportIssueScreen(): JSX.Element { setIssueData(data); setUpdateState(data.state); setUpdateDepartment(data.department ?? ''); - setUpdateClerk(data.clerk ?? ''); + setUpdateClerk(data.clerkUserDataId != null ? String(data.clerkUserDataId) : ''); }) .catch((e: Error) => setLoadError(e.message ?? 'Unknown error')) .finally(() => setIsLoading(false)); @@ -132,7 +137,11 @@ export default function RealunitSupportIssueScreen(): JSX.Element { await updateIssue(+id, { state: updateState || undefined, department: updateDepartment || undefined, - clerk: updateClerk || undefined, + ...(updateClerk !== '' + ? { clerkUserDataId: +updateClerk } + : issueData?.clerkUserDataId != null + ? { clerkUserDataId: null } + : {}), }); loadIssue(); } catch (e: unknown) { @@ -294,15 +303,15 @@ export default function RealunitSupportIssueScreen(): JSX.Element { value={updateClerk} onChange={(e) => setUpdateClerk(e.target.value)} > - {!issueData?.clerk && } - {updateClerk && !clerks.includes(updateClerk) && ( + + {updateClerk && !clerks.some((c) => String(c.userDataId) === updateClerk) && ( )} {clerks.map((c) => ( - ))} diff --git a/src/screens/support-dashboard-issue.screen.tsx b/src/screens/support-dashboard-issue.screen.tsx index 5a868922a..ce8a70c6f 100644 --- a/src/screens/support-dashboard-issue.screen.tsx +++ b/src/screens/support-dashboard-issue.screen.tsx @@ -16,6 +16,7 @@ import { useNavigation } from 'src/hooks/navigation.hook'; import { useSplitPane } from 'src/hooks/split-pane.hook'; import { ASSIGNABLE_DEPARTMENTS, + SupportClerk, SupportIssueInternalData, SupportMessageInfo, useSupportDashboard, @@ -45,7 +46,7 @@ export default function SupportDashboardIssueScreen(): JSX.Element { const [messages, setMessages] = useState([]); const [pendingCount, setPendingCount] = useState(0); const visibleIdsRef = useRef>(new Set()); - const [clerks, setClerks] = useState([]); + const [clerks, setClerks] = useState([]); // Update form state const [updateState, setUpdateState] = useState(''); @@ -97,7 +98,7 @@ export default function SupportDashboardIssueScreen(): JSX.Element { setIssueData(data); setUpdateState(data.state); setUpdateDepartment(data.department ?? ''); - setUpdateClerk(data.clerk ?? ''); + setUpdateClerk(data.clerkUserDataId != null ? String(data.clerkUserDataId) : ''); }) .catch((e: Error) => setLoadError(e.message ?? 'Unknown error')) .finally(() => setIsLoading(false)); @@ -182,7 +183,11 @@ export default function SupportDashboardIssueScreen(): JSX.Element { await updateIssue(+id, { state: updateState || undefined, department: updateDepartment || undefined, - clerk: updateClerk || undefined, + ...(updateClerk !== '' + ? { clerkUserDataId: +updateClerk } + : issueData?.clerkUserDataId != null + ? { clerkUserDataId: null } + : {}), }); loadIssue(); } catch (e: unknown) { @@ -480,15 +485,15 @@ export default function SupportDashboardIssueScreen(): JSX.Element { value={updateClerk} onChange={(e) => setUpdateClerk(e.target.value)} > - {!issueData?.clerk && } - {updateClerk && !clerks.includes(updateClerk) && ( + + {updateClerk && !clerks.some((c) => String(c.userDataId) === updateClerk) && ( )} {clerks.map((c) => ( - ))} From d21bea102a05aeb322d5771ba6109e9ceeb86661 Mon Sep 17 00:00:00 2001 From: joshuakrueger-dfx Date: Tue, 25 Aug 2026 21:11:42 +0200 Subject: [PATCH 2/5] fix(support): mock clerks as { userDataId, name } in RealUnit e2e The issue screen reads userDataId/name from GET /clerks. The Playwright fixture still sent string names, so the clerk select had no labels. --- e2e/realunit-support.spec.ts | 6 +++++- src/__tests__/realunit-dashboard.hook.test.ts | 10 ++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/e2e/realunit-support.spec.ts b/e2e/realunit-support.spec.ts index e66280992..68e317d1c 100644 --- a/e2e/realunit-support.spec.ts +++ b/e2e/realunit-support.spec.ts @@ -215,7 +215,10 @@ const COUNTS: Record = { Completed: 9, }; -const CLERKS: string[] = ['Rita Clerk', 'Tom Support']; +const CLERKS: { userDataId: number; name: string }[] = [ + { userDataId: 101, name: 'Rita Clerk' }, + { userDataId: 102, name: 'Tom Support' }, +]; // Detail for ISSUE_ID (7001), matching the OPEN_ISSUES[0] header fields. const ISSUE_DATA: SupportIssueInternalData = { @@ -228,6 +231,7 @@ const ISSUE_DATA: SupportIssueInternalData = { state: 'Pending', name: 'Alice Muster', clerk: 'Rita Clerk', + clerkUserDataId: 101, account: { id: 8001, status: 'Active', diff --git a/src/__tests__/realunit-dashboard.hook.test.ts b/src/__tests__/realunit-dashboard.hook.test.ts index df681aba1..e264f0d71 100644 --- a/src/__tests__/realunit-dashboard.hook.test.ts +++ b/src/__tests__/realunit-dashboard.hook.test.ts @@ -88,6 +88,16 @@ describe('useRealunitSupport', () => { expect(messages).toEqual([{ id: 1, author: 'Alice', created: 'now' }]); }); + it('getClerks returns { userDataId, name }[] from GET realunit/support/clerks', async () => { + mockCall.mockResolvedValue([{ userDataId: 3, name: 'Alex' }]); + const { result } = renderHook(() => useRealunitSupport()); + + const clerks = await result.current.getClerks(); + + expect(mockCall).toHaveBeenCalledWith({ url: 'realunit/support/clerks', method: 'GET' }); + expect(clerks).toEqual([{ userDataId: 3, name: 'Alex' }]); + }); + it('getMyClerk GETs realunit/support/clerk and trims the clerk name', async () => { mockCall.mockResolvedValue({ clerkUserDataId: 7, clerk: ' Ada ' }); const { result } = renderHook(() => useRealunitSupport()); From 142019490dba75030d03da1351fd80b50b30fe90 Mon Sep 17 00:00:00 2001 From: joshuakrueger-dfx Date: Wed, 26 Aug 2026 10:00:37 +0200 Subject: [PATCH 3/5] fix(support): omit unchanged clerk assignment and cover the issue screen --- docs/test-architecture.md | 11 ++ e2e/realunit-support.spec.ts | 1 + ...ort-dashboard-02-issue-chromium-darwin.png | Bin 0 -> 76853 bytes e2e/support-dashboard-issue.spec.ts | 139 ++++++++++++++++++ scripts/handbook/metadata.json | 2 +- src/__tests__/realunit-dashboard.hook.test.ts | 48 ++++++ src/__tests__/support-dashboard.hook.test.ts | 80 ++++++++++ src/hooks/realunit-support.hook.ts | 6 +- src/hooks/support-dashboard.hook.ts | 23 ++- src/screens/realunit-support-issue.screen.tsx | 25 ++-- .../support-dashboard-issue.screen.tsx | 20 +-- 11 files changed, 326 insertions(+), 29 deletions(-) create mode 100644 e2e/screenshots/baseline/support-dashboard-issue.spec.ts-support-dashboard-02-issue-chromium-darwin.png create mode 100644 e2e/support-dashboard-issue.spec.ts create mode 100644 src/__tests__/support-dashboard.hook.test.ts diff --git a/docs/test-architecture.md b/docs/test-architecture.md index 2e938cda0..660d85862 100644 --- a/docs/test-architecture.md +++ b/docs/test-architecture.md @@ -150,6 +150,17 @@ run does not prove for each one; the taxonomy and cross-repository entries live clerks list, not that the API returns those records or the logged-in staff member's `verifiedName`. The session is a synthetic unsigned JWT, so a green run also does not prove login or token verification. +- **The RealUnit support visual spec answers the support endpoints itself.** + `e2e/realunit-support.spec.ts` fulfils `GET /v1/realunit/support/list`, `/counts`, `/activity`, + `/clerks`, `/:id/data` and `/:id/messages` with synthetic `{ userDataId, name }[]` clerks and + `clerkUserDataId` on the issue fixture. A green run proves those fixtures render. It does not + prove that the API returns object clerks, that assignment writes `clerkUserDataId`, or that + login works — auth is a real admin token, feature data is not. +- **The DFX support issue visual spec answers the issue endpoints itself.** + `e2e/support-dashboard-issue.spec.ts` uses a synthetic unsigned Admin JWT and fulfils + `GET /v1/support/issue/clerks`, `/v1/support/issue/:id/data`, `/v1/support/issue/:uid` + (message thread) and staff bootstrap GETs. A green run proves the issue screen renders + that fixture, not that the API returns it or that login works. - **Full-stack guest assign/refund specs SQL-write `transaction.actionSecretHash`.** `e2e-stack/specs/transactions.spec.ts` (`seedActionSecret`) updates the hash directly. A green run does **not** prove that the mail/API path creates, hashes, or delivers the action secret. diff --git a/e2e/realunit-support.spec.ts b/e2e/realunit-support.spec.ts index 68e317d1c..22e69b040 100644 --- a/e2e/realunit-support.spec.ts +++ b/e2e/realunit-support.spec.ts @@ -119,6 +119,7 @@ interface SupportIssueInternalData { state: string; name: string; clerk?: string; + clerkUserDataId?: number; account: SupportIssueInternalAccountData; } diff --git a/e2e/screenshots/baseline/support-dashboard-issue.spec.ts-support-dashboard-02-issue-chromium-darwin.png b/e2e/screenshots/baseline/support-dashboard-issue.spec.ts-support-dashboard-02-issue-chromium-darwin.png new file mode 100644 index 0000000000000000000000000000000000000000..bddacfe56a02ddd0bf8c35b7f31ba764d5cd4059 GIT binary patch literal 76853 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
aZw8ntSwlLMr6 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 z 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 literal 0 HcmV?d00001 diff --git a/e2e/support-dashboard-issue.spec.ts b/e2e/support-dashboard-issue.spec.ts new file mode 100644 index 000000000..c906d2420 --- /dev/null +++ b/e2e/support-dashboard-issue.spec.ts @@ -0,0 +1,139 @@ +import { test, expect, Page, Route } from '@playwright/test'; + +/** + * E2E Visual Regression Test: DFX Support issue detail + * + * Auth is a synthetic Admin JWT. Staff GETs and the issue endpoints are mocked, so + * the suite does not need a live API. See docs/test-architecture.md. + */ + +const CUSTOMER_AUTHOR = 'Customer'; +const ISSUE_ID = 7001; +const ISSUE_UID = 'SI-7001-UID'; + +function jwt(): string { + const encode = (value: object) => Buffer.from(JSON.stringify(value)).toString('base64url'); + return `${encode({ alg: 'none', typ: 'JWT' })}.${encode({ + account: 1, + user: 1, + role: 'Admin', + exp: Math.floor(Date.now() / 1000) + 3600, + })}.synthetic`; +} + +const CLERKS = [ + { userDataId: 101, name: 'Rita Clerk' }, + { userDataId: 102, name: 'Tom Support' }, +]; + +const ISSUE_DATA = { + id: ISSUE_ID, + created: '2024-01-01T09:00:00.000Z', + uid: ISSUE_UID, + type: 'TransactionIssue', + department: 'Support', + reason: 'FundsNotReceived', + state: 'Pending', + name: 'Alice Muster', + clerk: 'Rita Clerk', + clerkUserDataId: 101, + account: { + id: 8001, + status: 'Active', + verifiedName: 'Alice Muster', + completeName: 'Alice Muster', + accountType: 'Personal', + kycLevel: '50', + depositLimit: 100000, + annualVolume: 25000, + kycHash: 'a1b2c3d4e5', + country: { name: 'Switzerland' }, + language: { name: 'English', symbol: 'EN' }, + }, +}; + +const MESSAGES = [ + { + id: 501, + author: CUSTOMER_AUTHOR, + message: 'Hello, I did not receive my funds for the last transaction.', + created: '2024-01-01T09:05:00.000Z', + }, + { + id: 502, + author: 'Rita Clerk', + message: 'Hi Alice, thanks for reaching out.', + created: '2024-01-01T10:30:00.000Z', + }, +]; + +const CLERKS_RE = /\/v1\/support\/issue\/clerks(?:\?|$)/; +const DATA_RE = /\/v1\/support\/issue\/(\d+)\/data(?:\?|$)/; +const THREAD_RE = /\/v1\/support\/issue\/SI-7001-UID(?:\?|$)/; + +async function json(route: Route, body: unknown): Promise { + await route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify(body) }); +} + +async function installIssueRoutes(page: Page): Promise { + await page.route('**/v1/**', async (route: Route) => { + const request = route.request(); + const url = request.url(); + const path = new URL(url).pathname; + + if (CLERKS_RE.test(url)) return json(route, CLERKS); + if (DATA_RE.test(url)) return json(route, ISSUE_DATA); + if (THREAD_RE.test(url) && request.method() === 'GET') return json(route, { messages: MESSAGES }); + + if ( + request.method() === 'GET' && + ['/v1/language', '/v1/fiat', '/v1/asset', '/v1/bankAccount', '/v1/country'].includes(path) + ) { + return json(route, []); + } + if (request.method() === 'GET' && path === '/v1/setting/infoBanner') { + return json(route, null); + } + if (request.method() === 'GET' && path === '/v1/support/issue/clerk') { + return json(route, { clerkUserDataId: 1, clerk: 'Rita Clerk' }); + } + + await route.continue(); + }); + + await page.route('**/v2/**', async (route: Route) => { + const request = route.request(); + const path = new URL(request.url()).pathname; + if (request.method() === 'GET' && path === '/v2/user') { + return json(route, { + id: 1, + activeAddress: { address: '0x0000000000000000000000000000000000000001', wallet: 'DFX' }, + addresses: [], + kyc: { level: 50, status: 'Completed' }, + language: { id: 1, name: 'English', symbol: 'EN' }, + }); + } + await route.continue(); + }); +} + +test.describe('Support Dashboard - issue detail', () => { + const token = jwt(); + + test('issue screen shows detail panels, clerk select and message thread', async ({ page }) => { + await installIssueRoutes(page); + + await page.goto(`/support/dashboard/issue/${ISSUE_ID}?session=${encodeURIComponent(token)}&lang=en`); + await page.waitForLoadState('networkidle'); + await page.waitForTimeout(1500); + + await expect(page.getByText('Issue Details')).toBeVisible(); + await expect(page.getByText(ISSUE_UID)).toBeVisible(); + await expect(page.locator('select').filter({ hasText: 'Rita Clerk' })).toHaveValue('101'); + + await expect(page).toHaveScreenshot('support-dashboard-02-issue.png', { + fullPage: true, + maxDiffPixels: 5000, + }); + }); +}); diff --git a/scripts/handbook/metadata.json b/scripts/handbook/metadata.json index 8cd77857e..4c543b42f 100644 --- a/scripts/handbook/metadata.json +++ b/scripts/handbook/metadata.json @@ -161,7 +161,7 @@ }, "support-dashboard": { "title": "Support-Dashboard", - "description": "Support-Dashboard: Übersicht und Detailansichten." + "description": "Support-Dashboard: Übersicht der offenen Tickets und die Ticket-Detailansicht mit Clerk-Zuweisung." }, "support-dashboard-overview": { "title": "Support-Dashboard Übersicht", diff --git a/src/__tests__/realunit-dashboard.hook.test.ts b/src/__tests__/realunit-dashboard.hook.test.ts index e264f0d71..4aae5f098 100644 --- a/src/__tests__/realunit-dashboard.hook.test.ts +++ b/src/__tests__/realunit-dashboard.hook.test.ts @@ -27,6 +27,7 @@ jest.mock('src/util/utils', () => ({ import { ResponseType } from '@dfx.swiss/react'; import { useRealunitCompliance } from '../hooks/realunit-compliance.hook'; import { useRealunitSupport } from '../hooks/realunit-support.hook'; +import { clerkAssignmentPayload, usableClerks } from '../hooks/support-dashboard.hook'; describe('useRealunitSupport', () => { beforeEach(() => { @@ -98,6 +99,17 @@ describe('useRealunitSupport', () => { expect(clerks).toEqual([{ userDataId: 3, name: 'Alex' }]); }); + it('getClerks drops entries without a finite userDataId', async () => { + mockCall.mockResolvedValue([ + { userDataId: 3, name: 'Alex' }, + { userDataId: Number.NaN, name: 'Broken' }, + { name: 'NoId' }, + ]); + const { result } = renderHook(() => useRealunitSupport()); + + await expect(result.current.getClerks()).resolves.toEqual([{ userDataId: 3, name: 'Alex' }]); + }); + it('getMyClerk GETs realunit/support/clerk and trims the clerk name', async () => { mockCall.mockResolvedValue({ clerkUserDataId: 7, clerk: ' Ada ' }); const { result } = renderHook(() => useRealunitSupport()); @@ -119,6 +131,42 @@ describe('useRealunitSupport', () => { }); }); +describe('clerkAssignmentPayload', () => { + it('omits the field when the selected clerk is unchanged', () => { + expect(clerkAssignmentPayload('101', 101)).toEqual({}); + }); + + it('sends the id when assigning a different clerk', () => { + expect(clerkAssignmentPayload('102', 101)).toEqual({ clerkUserDataId: 102 }); + }); + + it('sends null when clearing an existing assignment', () => { + expect(clerkAssignmentPayload('', 101)).toEqual({ clerkUserDataId: null }); + }); + + it('omits the field when already unassigned and the select is empty', () => { + expect(clerkAssignmentPayload('', null)).toEqual({}); + expect(clerkAssignmentPayload('')).toEqual({}); + }); + + it('omits the field when the selected value is not a finite id', () => { + expect(clerkAssignmentPayload('undefined', 101)).toEqual({}); + expect(clerkAssignmentPayload('NaN', 101)).toEqual({}); + }); +}); + +describe('usableClerks', () => { + it('keeps only entries with a finite userDataId and a name', () => { + expect( + usableClerks([ + { userDataId: 1, name: 'Ada' }, + { userDataId: Number.NaN, name: 'Bad' }, + { userDataId: 2, name: '' }, + ]), + ).toEqual([{ userDataId: 1, name: 'Ada' }]); + }); +}); + describe('useRealunitCompliance', () => { beforeEach(() => { mockCall.mockReset().mockResolvedValue(undefined); diff --git a/src/__tests__/support-dashboard.hook.test.ts b/src/__tests__/support-dashboard.hook.test.ts new file mode 100644 index 000000000..22d350733 --- /dev/null +++ b/src/__tests__/support-dashboard.hook.test.ts @@ -0,0 +1,80 @@ +import { renderHook } from '@testing-library/react'; + +const mockCall = jest.fn(); + +jest.mock('@dfx.swiss/react', () => ({ + useApi: () => ({ call: mockCall }), + Department: { SUPPORT: 'Support', COMPLIANCE: 'Compliance', MARKETING: 'Marketing' }, + TfaLevel: { STRICT: 'Strict' }, +})); + +jest.mock('../hooks/navigation.hook', () => ({ + useNavigation: () => ({ navigate: jest.fn() }), +})); + +import { useSupportDashboard } from '../hooks/support-dashboard.hook'; + +describe('useSupportDashboard', () => { + beforeEach(() => { + mockCall.mockReset().mockResolvedValue(undefined); + }); + + it('getClerks returns { userDataId, name }[] from GET support/issue/clerks', async () => { + mockCall.mockResolvedValue([{ userDataId: 3, name: 'Alex' }]); + const { result } = renderHook(() => useSupportDashboard()); + + const clerks = await result.current.getClerks(); + + expect(mockCall).toHaveBeenCalledWith({ url: 'support/issue/clerks', method: 'GET' }); + expect(clerks).toEqual([{ userDataId: 3, name: 'Alex' }]); + }); + + it('getClerks drops entries without a finite userDataId', async () => { + mockCall.mockResolvedValue([ + { userDataId: 3, name: 'Alex' }, + { userDataId: Number.NaN, name: 'Broken' }, + ]); + const { result } = renderHook(() => useSupportDashboard()); + + await expect(result.current.getClerks()).resolves.toEqual([{ userDataId: 3, name: 'Alex' }]); + }); + + it('getMyClerk GETs support/issue/clerk and trims the clerk name', async () => { + mockCall.mockResolvedValue({ clerkUserDataId: 7, clerk: ' Ada ' }); + const { result } = renderHook(() => useSupportDashboard()); + + await expect(result.current.getMyClerk()).resolves.toEqual({ clerkUserDataId: 7, clerk: 'Ada' }); + expect(mockCall).toHaveBeenCalledWith({ url: 'support/issue/clerk', method: 'GET' }); + }); + + it('getMyClerk returns undefined when clerk is null', async () => { + mockCall.mockResolvedValue({ clerkUserDataId: 7, clerk: null }); + const { result } = renderHook(() => useSupportDashboard()); + + await expect(result.current.getMyClerk()).resolves.toBeUndefined(); + }); + + it('updateIssue PUTs clerkUserDataId', async () => { + const { result } = renderHook(() => useSupportDashboard()); + + await result.current.updateIssue(42, { state: 'Completed', clerkUserDataId: 9 }); + + expect(mockCall).toHaveBeenCalledWith({ + url: 'support/issue/42', + method: 'PUT', + data: { state: 'Completed', clerkUserDataId: 9 }, + }); + }); + + it('updateIssue PUTs null to unassign', async () => { + const { result } = renderHook(() => useSupportDashboard()); + + await result.current.updateIssue(42, { clerkUserDataId: null }); + + expect(mockCall).toHaveBeenCalledWith({ + url: 'support/issue/42', + method: 'PUT', + data: { clerkUserDataId: null }, + }); + }); +}); diff --git a/src/hooks/realunit-support.hook.ts b/src/hooks/realunit-support.hook.ts index f3a32ae7b..ef3d52ee5 100644 --- a/src/hooks/realunit-support.hook.ts +++ b/src/hooks/realunit-support.hook.ts @@ -5,6 +5,7 @@ import { SupportIssueInternalData, SupportIssueListItem, SupportMessageInfo, + usableClerks, } from './support-dashboard.hook'; // RealUnit tenant support dashboard hook. Thin wrapper over the strictly customer-scoped `/v1/realunit/support/*` @@ -48,14 +49,15 @@ export function useRealunitSupport() { } async function getClerks(): Promise { - return call({ + const list = await call({ url: 'realunit/support/clerks', method: 'GET', }); + return usableClerks(list); } async function getMyClerk(): Promise<{ clerkUserDataId: number; clerk: string } | undefined> { - const result = await call<{ clerkUserDataId: number; clerk: string }>({ + const result = await call<{ clerkUserDataId: number; clerk: string | null }>({ url: 'realunit/support/clerk', method: 'GET', }); diff --git a/src/hooks/support-dashboard.hook.ts b/src/hooks/support-dashboard.hook.ts index 540d3c76e..d77029ce2 100644 --- a/src/hooks/support-dashboard.hook.ts +++ b/src/hooks/support-dashboard.hook.ts @@ -130,6 +130,24 @@ export interface SupportClerk { name: string; } +/** PUT payload for the clerk select: omit when unchanged, null to unassign, skip non-finite values. */ +export function clerkAssignmentPayload( + selected: string, + previousId?: number | null, +): { clerkUserDataId: number | null } | Record { + const previous = previousId ?? null; + if (selected === '') { + return previous != null ? { clerkUserDataId: null } : {}; + } + const nextId = Number(selected); + if (!Number.isFinite(nextId) || nextId === previous) return {}; + return { clerkUserDataId: nextId }; +} + +export function usableClerks(clerks: SupportClerk[]): SupportClerk[] { + return clerks.filter((c) => Number.isFinite(c.userDataId) && c.name); +} + export function useSupportDashboard() { // staff endpoints answer with HTTP 403 { code: 'TFA_REQUIRED' } when the session still needs 2FA; // useGuardedApi routes that into the bearer-based 2FA flow instead of surfacing a raw error @@ -177,14 +195,15 @@ export function useSupportDashboard() { } async function getClerks(): Promise { - return guardedCall({ + const list = await guardedCall({ url: 'support/issue/clerks', method: 'GET', }); + return usableClerks(list); } async function getMyClerk(): Promise<{ clerkUserDataId: number; clerk: string } | undefined> { - const result = await guardedCall<{ clerkUserDataId: number; clerk: string }>({ + const result = await guardedCall<{ clerkUserDataId: number; clerk: string | null }>({ url: 'support/issue/clerk', method: 'GET', }); diff --git a/src/screens/realunit-support-issue.screen.tsx b/src/screens/realunit-support-issue.screen.tsx index b8bdba7e6..782afb1f2 100644 --- a/src/screens/realunit-support-issue.screen.tsx +++ b/src/screens/realunit-support-issue.screen.tsx @@ -15,6 +15,7 @@ import { useStaffVerifiedName } from 'src/hooks/staff-verified-name.hook'; import { useSplitPane } from 'src/hooks/split-pane.hook'; import { ASSIGNABLE_DEPARTMENTS, + clerkAssignmentPayload, SupportClerk, SupportIssueInternalData, SupportMessageInfo, @@ -137,11 +138,7 @@ export default function RealunitSupportIssueScreen(): JSX.Element { await updateIssue(+id, { state: updateState || undefined, department: updateDepartment || undefined, - ...(updateClerk !== '' - ? { clerkUserDataId: +updateClerk } - : issueData?.clerkUserDataId != null - ? { clerkUserDataId: null } - : {}), + ...clerkAssignmentPayload(updateClerk, issueData?.clerkUserDataId), }); loadIssue(); } catch (e: unknown) { @@ -304,11 +301,14 @@ export default function RealunitSupportIssueScreen(): JSX.Element { onChange={(e) => setUpdateClerk(e.target.value)} > - {updateClerk && !clerks.some((c) => String(c.userDataId) === updateClerk) && ( - - )} + {updateClerk && + Number.isFinite(Number(updateClerk)) && + issueData?.clerk && + !clerks.some((c) => String(c.userDataId) === updateClerk) && ( + + )} {clerks.map((c) => ( - {updateClerk && !clerks.some((c) => String(c.userDataId) === updateClerk) && ( - - )} + {updateClerk && + Number.isFinite(Number(updateClerk)) && + issueData?.clerk && + !clerks.some((c) => String(c.userDataId) === updateClerk) && ( + + )} {clerks.map((c) => (