Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(fe:FSADT1-1603): CLIENT_EDITOR Client Location Section - Edit - Front-End #1428

Merged
merged 43 commits into from
Mar 7, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
9d69f04
add the Edit location button
fterra-encora Feb 13, 2025
61f2673
reuse staff location group component on the Client edit page
fterra-encora Feb 13, 2025
9ef8470
emit "save" location patch data
fterra-encora Feb 14, 2025
5bc823d
move conversion functions to the application Service module
fterra-encora Feb 17, 2025
9e78f85
call the PATCH client API
fterra-encora Feb 18, 2025
9bb6bca
fix json-patch path for addresses
fterra-encora Feb 18, 2025
4a41442
call API to deactivate/reactivate location
fterra-encora Feb 18, 2025
237079f
lock scroll to the bottom while location container shrinks
fterra-encora Feb 18, 2025
0357b89
test: LocationView
fterra-encora Feb 19, 2025
5935628
handle scroll on click Cancel
fterra-encora Feb 20, 2025
59c3eca
test LocationView new features
fterra-encora Feb 20, 2025
3cc8b14
update code interface for province and country
fterra-encora Feb 24, 2025
256afb0
update error messages
fterra-encora Feb 25, 2025
d8cdd08
auto-scroll to the top-notification error
fterra-encora Feb 26, 2025
1ec2f1a
validation check without side-effects
fterra-encora Feb 26, 2025
b5581f2
fix test
fterra-encora Feb 26, 2025
964fe4d
do not scroll to top on success
fterra-encora Feb 26, 2025
5b54cbb
test: save location
fterra-encora Feb 26, 2025
dcdb800
test: location patch prefix and duplicate name validation
fterra-encora Feb 26, 2025
7103ae5
do not auto-scroll to the error message anymore
fterra-encora Feb 27, 2025
7e394c2
test: fix e2e test
fterra-encora Feb 28, 2025
2779919
Merge branch 'main' into feat/FSADT1-1603
fterra-encora Feb 28, 2025
352b7a9
test: fix tests by increasing the viewport
fterra-encora Feb 28, 2025
70b6b97
test: fix test by waiting to load the provinces list
fterra-encora Feb 28, 2025
d3beafa
text: fix attempt by changing the viewport
fterra-encora Feb 28, 2025
c18f3e9
temp: run only the Location component
fterra-encora Feb 28, 2025
25ea47d
fix: local intercept
fterra-encora Feb 28, 2025
34866ea
restore tests
fterra-encora Feb 28, 2025
afdc70f
test: fix test
fterra-encora Feb 28, 2025
d4ec0f1
Update ClientDetailsPage.vue
mamartinezmejia Mar 4, 2025
bccd5be
Merge branch 'main' into feat/FSADT1-1603
mamartinezmejia Mar 4, 2025
2b6d8a3
Merge branch 'main' into feat/FSADT1-1603
mamartinezmejia Mar 5, 2025
ae863b8
Merge branch 'main' into feat/FSADT1-1603
mamartinezmejia Mar 5, 2025
75a4fab
update location name on accordion header
fterra-encora Mar 5, 2025
c55d339
cancel name change on accordion header
fterra-encora Mar 5, 2025
31cb6c0
Merge branch 'main' into feat/FSADT1-1603
mamartinezmejia Mar 6, 2025
6b0c231
select reason code for address change
fterra-encora Mar 6, 2025
512b72f
remove console logs
fterra-encora Mar 6, 2025
60d7234
fix reasons patch format
fterra-encora Mar 6, 2025
26c207f
fix: select reason for address change
fterra-encora Mar 6, 2025
fcbed03
simplify code to manage change reasons
fterra-encora Mar 6, 2025
9bcc85a
test: select reason for Address change
fterra-encora Mar 6, 2025
6cc121a
Merge branch 'main' into feat/FSADT1-1603
paulushcgcj Mar 7, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
216 changes: 201 additions & 15 deletions frontend/cypress/e2e/pages/ClientDetailsPage.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ describe("Client Details Page", () => {
});

const testReadonly = (rawSelector: string, value?: string) => {
const selector = `div${rawSelector}`;
const selector = `:is(div, span)${rawSelector}`;
cy.get(selector).should("be.visible");
if (value !== undefined) {
cy.get(selector).contains(value);
Expand Down Expand Up @@ -268,14 +268,11 @@ describe("Client Details Page", () => {

expect(requestBody).to.deep.include({
op: "add",
path: "/reasons/0/reason",
value: "R1",
});

expect(requestBody).to.deep.include({
op: "add",
path: "/reasons/0/field",
value: "clientStatusCode",
path: "/reasons/0",
value: {
field: "clientStatusCode",
reason: "R1",
},
});
});
});
Expand Down Expand Up @@ -311,7 +308,7 @@ describe("Client Details Page", () => {

it("displays the location name on the accordion's title", () => {
cy.get("#location-00 [slot='title']").contains("00 - Mailing address");
cy.get("#location-01 [slot='title']").contains("01 - Accountant's address");
cy.get("#location-01 [slot='title']").contains("01 - Accountant address");
cy.get("#location-02 [slot='title']").contains("02 - Warehouse");
});

Expand All @@ -322,17 +319,17 @@ describe("Client Details Page", () => {
});
});

describe("2 locations - 1 deactivated and 1 active", () => {
describe("2 locations - 1 active and 1 deactivated", () => {
before(function () {
init.call(this);
cy.visit("/clients/details/gd");
});
it("displays the tag Deactivated when location is expired", () => {
cy.get("cds-tag#location-00-deactivated").contains("Deactivated");
it("doesn't display the tag Deactivated when location is not expired", () => {
cy.get("cds-tag#location-00-deactivated").should("not.exist");
});

it("doesn't display the tag Deactivated when location is not expired", () => {
cy.get("cds-tag#location-01-deactivated").should("not.exist");
it("displays the tag Deactivated when location is expired", () => {
cy.get("cds-tag#location-01-deactivated").contains("Deactivated");
});
});

Expand Down Expand Up @@ -389,6 +386,195 @@ describe("Client Details Page", () => {
cy.get("#location-02 cds-accordion-item").should("have.attr", "open");
});
});

describe("when role:CLIENT_EDITOR", () => {
describe("name duplication", () => {
beforeEach(() => {
cy.visit("/clients/details/g");

// Clicks to expand the accordion
cy.get("#location-00 [slot='title']").click();

cy.get("#location-00-EditBtn").click();

cy.clearFormEntry("#name_0");

// This is the same name of the third location
cy.fillFormEntry("#name_0", "Warehouse");
});

it("shows the error on field Location name", () => {
cy.checkInputErrorMessage("#name_0", "This value is already in use");

cy.get("#location-00-SaveBtn").shadow().find("button").should("be.disabled");
});
});
describe("save", () => {
describe("on success", { testIsolation: false }, () => {
const getClientDetailsCounter = {
count: 0,
};

let patchClientDetailsRequest;
before(function () {
init.call(this);

cy.intercept(
{
method: "GET",
pathname: "/api/clients/details/*",
},
(req) => {
getClientDetailsCounter.count++;
req.continue();
},
).as("getClientDetails");

cy.intercept(
{
method: "PATCH",
pathname: "/api/clients/details/*",
},
(req) => {
patchClientDetailsRequest = req;
req.continue();
},
).as("patchClientDetails");

cy.visit("/clients/details/g");
cy.wait("@getClientDetails");

// Clicks to expand the accordion
cy.get("#location-00 [slot='title']").click();

cy.get("#location-00-EditBtn").click();
cy.clearFormEntry("#emailAddress_0");
cy.get("#location-00-SaveBtn").click();
cy.wait("@getClientDetails");
});

it("prefixes the path with the corresponding location code", () => {
expect(patchClientDetailsRequest.body[0].path).to.eq("/addresses/00/emailAddress");
});

it("shows the success toast", () => {
cy.get("cds-toast-notification[kind='success']").should("be.visible");
});

it("reloads data", () => {
// Called twice - one for the initial loading and one after saving.
cy.wrap(getClientDetailsCounter).its("count").should("eq", 2);
});

it("gets back into view mode", () => {
// Fields that belong to the form (edit mode)
testHidden("#city_0");
testHidden("#emailAddress_0");
testHidden("[data-id='input-notes_0']");

cy.get("#location-00-SaveBtn").should("not.exist");

testReadonly("#location-00-city-province");
testReadonly("#location-00-emailAddress");
testReadonly("#location-00-notes");

cy.get("#location-00-EditBtn").should("be.visible");
});
});

describe("on failure", { testIsolation: false }, () => {
before(function () {
init.call(this);

cy.visit("/clients/details/g");

// Clicks to expand the accordion
cy.get("#location-00 [slot='title']").click();

cy.get("#location-00-EditBtn").click();
cy.fillFormEntry("[data-id='input-notes_0']", "error", { area: true });
cy.get("#location-00-SaveBtn").click();
});

it("shows the error toast", () => {
cy.get("cds-toast-notification[kind='error']").should("be.visible");
});

it("stays in edit mode", () => {
cy.get("#city_0").should("be.visible");
cy.get("#emailAddress_0").should("be.visible");
cy.get("[data-id='input-notes_0']").should("be.visible");

cy.get("#location-00-SaveBtn").should("be.visible");
});
});

describe("with reason modal", { testIsolation: false }, () => {
beforeEach(function () {
init.call(this);

cy.intercept("PATCH", "/api/clients/details/*").as("saveClientDetails");

cy.intercept("GET", "/api/codes/update-reasons/*/*").as("getReasonsList");

cy.visit("/clients/details/g");

// Clicks to expand the accordion
cy.get("#location-00 [slot='title']").click();

cy.get("#location-00-EditBtn").click();
cy.fillFormEntry("#addr_0", "2 Update Av");
cy.fillFormEntry("#city_0", "Updateland");
cy.selectFormEntry("#province_0", "Quebec");
cy.get("#location-00-SaveBtn").click();

cy.wait("@getReasonsList").then(({ request }) => {
// requests the list of options related to Address change
expect(request.url.endsWith("/ADDR")).to.eq(true);
});
});

it("opens the reason modal and sends the correct PATCH request with reasons", () => {
cy.get("#reason-modal").should("be.visible");

cy.get("#input-reason-0").should("exist");

// Only one reason should be required
cy.get("#input-reason-1").should("not.exist");

cy.get("#input-reason-0").find('[part="trigger-button"]').click();

cy.get("#input-reason-0")
.find("cds-dropdown-item")
.first()
.should("be.visible")
.click();

cy.get("#reasonSaveBtn").click();

cy.wait("@saveClientDetails").then((interception) => {
const requestBody = interception.request.body;

cy.log("Request Body:", JSON.stringify(requestBody));

expect(requestBody).to.deep.include({
op: "add",
path: "/reasons/0",
value: {
field: "/addresses/00",
reason: "R1",
},
});

// Only 1 "add" operation (the reason one)
expect((requestBody as any[]).filter((item) => item.op === "add")).to.have.lengthOf(
1,
);
});
});
});
});
});
});

describe("contacts tab", () => {
Expand Down
4 changes: 3 additions & 1 deletion frontend/cypress/support/component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ import './commands'
import { mount } from 'cypress/vue'
import '@cypress/code-coverage/support'
import VueDOMPurifyHTML from "vue-dompurify-html";
import '@/styles'
import '@/styles';
import directivesMap from '@/directivesMap';

declare global {
namespace Cypress {
Expand All @@ -18,6 +19,7 @@ declare global {

Cypress.Commands.add('mount', (component, options = {}) => {
options.global = options.global || {};
options.global.directives = directivesMap;
options.global.plugins = options.global.plugins || [];
options.global.plugins.push(VueDOMPurifyHTML);

Expand Down
2 changes: 1 addition & 1 deletion frontend/cypress/support/cypress.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ declare namespace Cypress {
fillFormEntry(field: string, value: string, delayMS?: number, area?: boolean): Chainable<void>;
fillFormEntry(field: string, value: string, options: FillFormEntryOptions): Chainable<void>;
clearFormEntry(field: string, area?: boolean): Chainable<void>;
selectFormEntry(field: string, value: string, box: boolean): Chainable<void>;
selectFormEntry(field: string, value: string): Chainable<void>;
markCheckbox(field: string): Chainable<void>;
unmarkCheckbox(field: string): Chainable<void>;
selectAutocompleteEntry(
Expand Down
5 changes: 4 additions & 1 deletion frontend/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@
"vite": "^5.4.10",
"vite-plugin-istanbul": "^5.0.0",
"vitest": "^3.0.5",
"vue-component-type-helpers": "^2.2.2",
"vue-eslint-parser": "^9.4.3",
"vue-svg-loader": "^0.16.0",
"vue-tsc": "^2.2.0",
Expand Down
35 changes: 34 additions & 1 deletion frontend/src/assets/styles/global.scss
Original file line number Diff line number Diff line change
Expand Up @@ -829,11 +829,17 @@ cds-actionable-notification * {
&--stretched {
cds-button {
flex: 1;

&::part(button) {
// We don't need this padding since the button is already stretched thanks to "flex: 1".
// This allows adjacent buttons to have the same size.
padding-inline-end: unset;
}
}
}
}

.form-edit {
.form-edit, .tab-form {
display: flex;
flex-direction: column;
gap: 2rem;
Expand All @@ -845,6 +851,10 @@ cds-actionable-notification * {
}
}

.tab-form {
max-width: 36rem;
}

.frame-01 {
align-self: stretch;
display: flex;
Expand Down Expand Up @@ -1194,6 +1204,21 @@ cds-accordion-item:not([open]) {
align-items: end;
}

.grid {
display: grid;
column-gap: 1rem;
row-gap: inherit;
align-items: end;

&--2-per-row {
grid-template-columns: 1fr 1fr;
}

&--3-per-row {
grid-template-columns: 1fr 1fr 1fr;
}
}

.input-with-instruction {
display: flex;
flex-direction: column;
Expand Down Expand Up @@ -1523,6 +1548,14 @@ cds-accordion-item::part(expando) {
min-block-size: 3rem;
}

cds-accordion-item[open]::part(cds--accordion__wrapper) {
/*
Fixes issue where accordions would not auto-adjust size (height) according to its content, when
it grows dynamically.
*/
max-block-size: unset;
}

cds-accordion-item[open]:not([disabled])::part(content),
:host(cds-accordion-item[open]:not([disabled]))
.cds-ce--accordion__content--md {
Expand Down
Loading
Loading