diff --git a/frontend/cypress/e2e/pages/ClientDetailsPage.cy.ts b/frontend/cypress/e2e/pages/ClientDetailsPage.cy.ts new file mode 100644 index 0000000000..e7d280b66e --- /dev/null +++ b/frontend/cypress/e2e/pages/ClientDetailsPage.cy.ts @@ -0,0 +1,22 @@ +describe("Client Details Page", () => { + beforeEach(() => { + cy.visit("/"); + + cy.login("uattest@gov.bc.ca", "Uat Test", "idir", { + given_name: "James", + family_name: "Baxter", + "cognito:groups": ["CLIENT_VIEWER"], + }); + + cy.visit("/clients/0"); + }); + + it("renders the page skeleton", () => { + cy.get("cds-breadcrumb").should("contain", "Client search"); + cy.contains("h2", "Client summary"); + cy.contains("cds-tab", "Client locations"); + cy.contains("cds-tab", "Client contacts"); + cy.contains("cds-tab", "Related clients"); + cy.contains("cds-tab", "Activity log"); + }); +}); diff --git a/frontend/cypress/e2e/pages/SearchPage.cy.ts b/frontend/cypress/e2e/pages/SearchPage.cy.ts index 082d4bb125..115fb9fc8d 100644 --- a/frontend/cypress/e2e/pages/SearchPage.cy.ts +++ b/frontend/cypress/e2e/pages/SearchPage.cy.ts @@ -41,7 +41,25 @@ describe("Search Page", () => { }); }; - beforeEach(() => { + const setupFeatureFlag = (ctx: Mocha.Context) => { + const titlePath = ctx.currentTest.titlePath(); + for (const title of titlePath.reverse()) { + const ffName = "STAFF_CLIENT_DETAIL"; + + if (!title.includes(ffName)) continue; + + const suffix = title.split(ffName)[1]; + const words = suffix.split(" "); + const value = !!words.find((cur) => ["on", "true"].includes(cur)); + + cy.addToLocalStorage("VITE_FEATURE_FLAGS", JSON.stringify({ [ffName]: value })); + + // No need to continue looking up in the titlePath + break; + } + }; + + beforeEach(function () { // reset counters predictiveSearchCounter.count = 0; fullSearchCounter.count = 0; @@ -74,6 +92,8 @@ describe("Search Page", () => { }, ).as("fullSearch"); + setupFeatureFlag(this); + cy.viewport(1920, 1080); cy.visit("/"); @@ -160,14 +180,24 @@ describe("Search Page", () => { cy.get("#search-box").find(`cds-combo-box-item[data-id="${clientNumber}"]`).click(); }); it("navigates to the client details", () => { - const greenDomain = "green-domain.com"; cy.get("@windowOpen").should( "be.calledWith", - `https://${greenDomain}/int/client/client02MaintenanceAction.do?bean.clientNumber=${clientNumber}`, + `/clients/${clientNumber}`, "_blank", "noopener", ); }); + describe("and STAFF_CLIENT_DETAIL is turned off", () => { + it("navigates to the client details in the legacy application", () => { + const greenDomain = "green-domain.com"; + cy.get("@windowOpen").should( + "be.calledWith", + `https://${greenDomain}/int/client/client02MaintenanceAction.do?bean.clientNumber=${clientNumber}`, + "_blank", + "noopener", + ); + }); + }); }); describe("and clicks the Search button", () => { @@ -207,14 +237,24 @@ describe("Search Page", () => { cy.get("cds-table").contains("cds-table-row", clientNumber).click(); }); it("navigates to the client details", () => { - const greenDomain = "green-domain.com"; cy.get("@windowOpen").should( "be.calledWith", - `https://${greenDomain}/int/client/client02MaintenanceAction.do?bean.clientNumber=${clientNumber}`, + `/clients/${clientNumber}`, "_blank", "noopener", ); }); + describe("and STAFF_CLIENT_DETAIL is turned off", () => { + it("navigates to the client details in the legacy application", () => { + const greenDomain = "green-domain.com"; + cy.get("@windowOpen").should( + "be.calledWith", + `https://${greenDomain}/int/client/client02MaintenanceAction.do?bean.clientNumber=${clientNumber}`, + "_blank", + "noopener", + ); + }); + }); }); describe("and clicks the Next page button on the table footer", () => { diff --git a/frontend/cypress/support/cypress.d.ts b/frontend/cypress/support/cypress.d.ts index 99d13bd775..eb7cae3411 100644 --- a/frontend/cypress/support/cypress.d.ts +++ b/frontend/cypress/support/cypress.d.ts @@ -6,17 +6,12 @@ declare namespace Cypress { addToSessionStorage(key: string, value: any): Chainable; expireSessionStorage(key: string): Chainable; expireCookie(name: string): Chainable; - login(email: string, name: string, provider: string, extras: any = "{}"): Chainable; + login(email: string, name: string, provider: string, extras?: any): Chainable; logout(): Chainable; getMany(names: string[]): Chainable; - fillFormEntry( - field: string, - value: string, - delayMS: number = 10, - area: boolean = false, - ): Chainable; + fillFormEntry(field: string, value: string, delayMS?: number, area?: boolean): Chainable; fillFormEntry(field: string, value: string, options: FillFormEntryOptions): Chainable; - clearFormEntry(field: string, area: boolean = false): Chainable; + clearFormEntry(field: string, area?: boolean): Chainable; selectFormEntry(field: string, value: string, box: boolean): Chainable; markCheckbox(field: string): Chainable; unmarkCheckbox(field: string): Chainable; @@ -24,7 +19,7 @@ declare namespace Cypress { field: string, value: string, dataid: string, - delayTarget: string = "", + delayTarget?: string, ): Chainable; checkInputErrorMessage(field: string, message: string): Chainable; checkAutoCompleteErrorMessage(field: string, message: string): Chainable; diff --git a/frontend/openshift.configmap.dev.yml b/frontend/openshift.configmap.dev.yml index edd1423759..ba7b485b09 100644 --- a/frontend/openshift.configmap.dev.yml +++ b/frontend/openshift.configmap.dev.yml @@ -22,4 +22,4 @@ objects: name: ${NAME}-${ZONE}-${COMPONENT}-config data: params.js: | - window.localStorage.setItem('VITE_FEATURE_FLAGS','{}'); + window.localStorage.setItem('VITE_FEATURE_FLAGS','{"STAFF_CLIENT_DETAIL":true}'); diff --git a/frontend/openshift.configmap.test.yml b/frontend/openshift.configmap.test.yml index edd1423759..ba7b485b09 100644 --- a/frontend/openshift.configmap.test.yml +++ b/frontend/openshift.configmap.test.yml @@ -22,4 +22,4 @@ objects: name: ${NAME}-${ZONE}-${COMPONENT}-config data: params.js: | - window.localStorage.setItem('VITE_FEATURE_FLAGS','{}'); + window.localStorage.setItem('VITE_FEATURE_FLAGS','{"STAFF_CLIENT_DETAIL":true}'); diff --git a/frontend/package.json b/frontend/package.json index 748ed3e9da..f5950a3687 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -36,7 +36,7 @@ "posttest:component": "mv reports/.nyc_report reports/component", "test:unit": "cross-env VITE_NODE_ENV=test NODE_ENV=test vitest run --coverage", "posttest:unit": "mv reports/.vite_report reports/unit", - "test:e2e": "cross-env VITE_NODE_ENV=test VITE_GREEN_DOMAIN=green-domain.com start-server-and-test preview http://127.0.0.1:3000 'cypress run --headless'", + "test:e2e": "cross-env VITE_NODE_ENV=test VITE_GREEN_DOMAIN=green-domain.com VITE_FEATURE_FLAGS={\\\"STAFF_CLIENT_DETAIL\\\":true} start-server-and-test preview http://127.0.0.1:3000 'cypress run --headless'", "posttest:e2e": "mv reports/.nyc_report reports/e2e", "pretest:report:merge": "rm -rf reports-merge && mkdir -p reports-merge && for name in component e2e unit; do cp reports/$name/coverage-final.json reports-merge/$name.json; done", "test:report:merge": "mkdir -p .nyc_output && rm -rf coverage && nyc --config nyc.config.json merge reports-merge && mv coverage.json .nyc_output/out.json && nyc --config nyc.config.json report --reporter lcov --reporter text-summary --report-dir coverage --temp-dir .nyc_output", diff --git a/frontend/src/assets/styles/global.scss b/frontend/src/assets/styles/global.scss index 1d2847927a..dbfdc12751 100644 --- a/frontend/src/assets/styles/global.scss +++ b/frontend/src/assets/styles/global.scss @@ -506,12 +506,24 @@ cds-accordion-item::part(title) { letter-spacing: 0.01rem; } +cds-tab > div { + color: var(--light-theme-text-text-primary, #131315); + font-size: var(--heading-compact-02-font-size); + font-style: normal; + letter-spacing: 0.01rem; + + width: 9.75rem; + display: flex; + justify-content: space-between; + align-items: center; +} + .light-theme-text-text-primary { color: var(--light-theme-text-text-primary, #131315) !important; } .light-theme-text-text-secondary { - color: var(--light-theme-text-text-secondary, #606062); + color: var(--light-theme-text-text-secondary, #606062) !important; } /* @@ -1395,7 +1407,9 @@ cds-side-nav-items.lower-side-nav { } .table-list, -.submission-content { +.submission-content, +.client-details-screen, +.client-details-content { padding: 2.5rem 0rem 2.5rem 16rem; display: flex; flex-direction: column; @@ -1416,12 +1430,26 @@ cds-side-nav { z-index: 10; } -.submission-content { +.submission-content, .client-details-screen, .client-details-content { padding: 2.5rem 2rem; gap: 3rem; flex: 4; } +.client-details-screen { + padding-left: 0; + padding-right: 0; + gap: 0; +} + +.client-details-content { + padding-top: 0; + padding-bottom: 0; + flex-grow: 0; + box-sizing: border-box; + width: 100%; +} + cds-accordion-item[open]:not([disabled])::part(content), :host(cds-accordion-item[open]:not([disabled])) .cds-ce--accordion__content--md { @@ -1446,13 +1474,13 @@ cds-accordion-item[open]:not([disabled])::part(content), margin-left: 2rem; } -.submission-header { +.resource-header { display: flex; flex-direction: column; gap: 0.5rem; } -.submission-details--title { +.resource-details--title { display: flex; align-items: flex-start; gap: 1rem; @@ -1725,6 +1753,13 @@ div.internal-grouping-01:has(svg.warning) span.body-compact-01 { width: 7.875rem; } +.tab-panel { + display: flex; + padding: 2.5rem; + gap: 2rem; + background: var(--light-theme-layer-layer-01, #f3f3f5); +} + /* Small (up to 671px) */ @media screen and (max-width: 671px) { :root { @@ -1887,10 +1922,20 @@ div.internal-grouping-01:has(svg.warning) span.body-compact-01 { width: 0rem; } - .submission-content { + .submission-content, .client-details-screen, .client-details-content { padding: 2.5rem 1rem !important; } + .client-details-screen { + padding-left: 0; + padding-right: 0; + } + + .client-details-content { + padding-top: 0; + padding-bottom: 0; + } + .grouping-10 { flex-direction: column; flex-wrap: nowrap; @@ -1920,7 +1965,7 @@ div.internal-grouping-01:has(svg.warning) span.body-compact-01 { .paginator { width: 100%; } - .submission-details--title svg { + .resource-details--title svg { width: 5rem; } @@ -2021,10 +2066,20 @@ div.internal-grouping-01:has(svg.warning) span.body-compact-01 { padding: 2.5rem 0rem; } - .submission-content { + .submission-content, .client-details-screen, .client-details-content { padding: 2.5rem 2rem; } + .client-details-screen { + padding-left: 0; + padding-right: 0; + } + + .client-details-content { + padding-top: 0; + padding-bottom: 0; + } + .paginator { width: 100%; } @@ -2089,7 +2144,7 @@ div.internal-grouping-01:has(svg.warning) span.body-compact-01 { div#screen div#title { margin-bottom: 2rem; } - .submission-content { + .submission-content, .client-details-screen, .client-details-content { --padding-right: 2rem; --padding-left: 18.5rem; padding: 2.5rem var(--padding-right) 2.5rem var(--padding-left); @@ -2098,6 +2153,16 @@ div.internal-grouping-01:has(svg.warning) span.body-compact-01 { (var(--padding-right) + var(--padding-left) + var(--scroll-bar-width)) ); } + .client-details-screen { + --padding-right: 0; + --padding-left: 16rem; + } + .client-details-content { + padding-top: 0; + padding-bottom: 0; + --padding-right: 2.5rem; + --padding-left: 2.5rem; + } div.content:has(div.staff svg.submission-badge) { margin-left: 16rem; @@ -2168,7 +2233,7 @@ div.internal-grouping-01:has(svg.warning) span.body-compact-01 { margin-bottom: 2rem; } - .submission-content { + .submission-content, .client-details-screen, .client-details-content { --padding-right: 2rem; --padding-left: 18.5rem; padding: 2.5rem var(--padding-right) 2.5rem var(--padding-left); @@ -2178,6 +2243,18 @@ div.internal-grouping-01:has(svg.warning) span.body-compact-01 { ); } + .client-details-screen { + --padding-right: 0; + --padding-left: 16rem; + } + + .client-details-content { + padding-top: 0; + padding-bottom: 0; + --padding-right: 2.5rem; + --padding-left: 2.5rem + } + div.content:has(div.frame-03 svg.submission-badge) { margin-left: 12rem; } @@ -2228,7 +2305,7 @@ div.internal-grouping-01:has(svg.warning) span.body-compact-01 { margin-bottom: 2rem; } - .submission-content { + .submission-content, .client-details-screen, .client-details-content { --padding-right: 2rem; --padding-left: 18.5rem; padding: 2.5rem var(--padding-right) 2.5rem var(--padding-left); @@ -2238,6 +2315,18 @@ div.internal-grouping-01:has(svg.warning) span.body-compact-01 { ); } + .client-details-screen { + --padding-right: 0; + --padding-left: 16rem; + } + + .client-details-content { + padding-top: 0; + padding-bottom: 0; + --padding-right: 2.5rem; + --padding-left: 2.5rem + } + div.content:has(div.frame-03 svg.submission-badge) { margin-left: 12rem; } @@ -2272,7 +2361,7 @@ div.internal-grouping-01:has(svg.warning) span.body-compact-01 { margin-bottom: 2rem; } - .submission-content { + .submission-content, .client-details-screen, .client-details-content { --padding-right: 2.5rem; --padding-left: 18.5rem; padding: 2.5rem var(--padding-right) 2.5rem var(--padding-left); @@ -2282,6 +2371,18 @@ div.internal-grouping-01:has(svg.warning) span.body-compact-01 { ); } + .client-details-screen { + --padding-right: 0; + --padding-left: 16rem; + } + + .client-details-content { + padding-top: 0; + padding-bottom: 0; + --padding-right: 2.5rem; + --padding-left: 2.5rem + } + div.content:has(div.frame-03 svg.submission-badge) { margin-left: 12rem; } diff --git a/frontend/src/pages/ClientDetailsPage.vue b/frontend/src/pages/ClientDetailsPage.vue new file mode 100644 index 0000000000..d243483583 --- /dev/null +++ b/frontend/src/pages/ClientDetailsPage.vue @@ -0,0 +1,93 @@ + + + diff --git a/frontend/src/pages/SearchPage.vue b/frontend/src/pages/SearchPage.vue index b0972d4f41..4eae7af23b 100644 --- a/frontend/src/pages/SearchPage.vue +++ b/frontend/src/pages/SearchPage.vue @@ -20,7 +20,7 @@ import useSvg from "@/composables/useSvg"; // @ts-ignore import Search16 from "@carbon/icons-vue/es/search/16"; -import { greenDomain } from "@/CoreConstants"; +import { greenDomain, featureFlags } from "@/CoreConstants"; import { isAscii, isMaxSizeMsg, @@ -149,7 +149,9 @@ const searchResultToText = (searchResult: ClientSearchResult): string => { const openClientDetails = (clientCode: string) => { if (clientCode) { - const url = `https://${greenDomain}/int/client/client02MaintenanceAction.do?bean.clientNumber=${clientCode}`; + const url = featureFlags.STAFF_CLIENT_DETAIL + ? `/clients/${clientCode}` + : `https://${greenDomain}/int/client/client02MaintenanceAction.do?bean.clientNumber=${clientCode}`; window.open(url, "_blank", "noopener"); } }; diff --git a/frontend/src/pages/SubmissionReviewPage.vue b/frontend/src/pages/SubmissionReviewPage.vue index bba10385a1..d13fe20f38 100644 --- a/frontend/src/pages/SubmissionReviewPage.vue +++ b/frontend/src/pages/SubmissionReviewPage.vue @@ -336,7 +336,7 @@ const isProcessing = computed(() => {