-
Notifications
You must be signed in to change notification settings - Fork 34
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(quantic): quantic user actions session component created (#4473)
## [SFINT-5678](https://coveord.atlassian.net/browse/SFINT-5678) ### Quantic User Actions Session component created The `QuanticUserActionsSession` component displays all the user actions that took place during a specific user session. This component will be used by the Quantic User Actions Timeline component that displayed the whole timeline containing two following sessions and two preceding sessions and the ticket creation session, ## Demo https://github.com/user-attachments/assets/ba289093-f8b8-494c-bc9e-a4f54dd80c9e #### Link to mockups: https://www.figma.com/design/tc1NDbxceu3tW1UjFIt8cm/Salesforce%3A-Quantic-Insight-Panel?node-id=204-13558&t=FtqdEiwgSTdxArJZ-0 [SFINT-5678]: https://coveord.atlassian.net/browse/SFINT-5678?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ --------- Co-authored-by: Simon Milord <[email protected]>
- Loading branch information
1 parent
7add130
commit 0882dbc
Showing
7 changed files
with
452 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
269 changes: 269 additions & 0 deletions
269
...pp/main/default/lwc/quanticUserActionsSession/__tests__/quanticUserActionsSession.test.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,269 @@ | ||
// @ts-ignore | ||
import quanticUserActionsSession from 'c/quanticUserActionsSession'; | ||
// @ts-ignore | ||
import {createElement} from 'lwc'; | ||
|
||
const selectors = { | ||
sessionDateIcon: '[data-test="session-start__date-icon"]', | ||
sessionDate: '[data-test="session-start__date"]', | ||
showMoreActions: '[data-test="session__show-more-actions-button"]', | ||
userActions: '[data-test="session__user-actions"] c-quantic-user-action', | ||
userActionsAferTicketCreation: | ||
'[data-test="session__user-actions-after-ticket-creation"] c-quantic-user-action', | ||
}; | ||
|
||
function createTestComponent(options) { | ||
const element = createElement('c-quantic-user-actions-session', { | ||
is: quanticUserActionsSession, | ||
}); | ||
for (const [key, value] of Object.entries(options)) { | ||
element[key] = value; | ||
} | ||
|
||
document.body.appendChild(element); | ||
return element; | ||
} | ||
|
||
// Helper function to wait until the microtask queue is empty. | ||
function flushPromises() { | ||
// eslint-disable-next-line @lwc/lwc/no-async-operation | ||
return new Promise((resolve) => setTimeout(resolve, 0)); | ||
} | ||
|
||
describe('c-quantic-user-actions-session', () => { | ||
function cleanup() { | ||
// The jsdom instance is shared across test cases in a single file so reset the DOM | ||
while (document.body.firstChild) { | ||
document.body.removeChild(document.body.firstChild); | ||
} | ||
jest.clearAllMocks(); | ||
} | ||
|
||
afterEach(() => { | ||
cleanup(); | ||
}); | ||
|
||
describe('when the user action session does not contain a ticket creation action', () => { | ||
const exampleActions = [ | ||
{ | ||
actionType: 'SEARCH', | ||
timestamp: new Date('2024-09-25T05:08Z').getTime(), | ||
query: 'example query', | ||
}, | ||
{ | ||
actionType: 'SEARCH', | ||
timestamp: new Date('2024-09-25T05:07Z').getTime(), | ||
query: 'example query', | ||
}, | ||
]; | ||
|
||
describe('the session start date', () => { | ||
it('should display the session start date without the icon', async () => { | ||
const element = createTestComponent({ | ||
userActions: exampleActions, | ||
startTimestamp: new Date('2024-09-25T05:07Z'), | ||
}); | ||
await flushPromises(); | ||
|
||
const sessionDateIcon = element.shadowRoot.querySelector( | ||
selectors.sessionDateIcon | ||
); | ||
const sessionDate = element.shadowRoot.querySelector( | ||
selectors.sessionDate | ||
); | ||
|
||
expect(sessionDateIcon).toBeNull(); | ||
expect(sessionDate).not.toBeNull(); | ||
|
||
expect(sessionDate.textContent).toBe('Wed. September 25, 2024'); | ||
}); | ||
}); | ||
|
||
describe('the show more actions button', () => { | ||
it('should not show the show more actions button', async () => { | ||
const element = createTestComponent({ | ||
userActions: exampleActions, | ||
startTimestamp: new Date('2024-09-25T05:07Z'), | ||
}); | ||
await flushPromises(); | ||
|
||
const showMoreActions = element.shadowRoot.querySelector( | ||
selectors.showMoreActions | ||
); | ||
|
||
expect(showMoreActions).toBeNull(); | ||
}); | ||
}); | ||
|
||
describe('the session user actions', () => { | ||
it('should properly display the user actions', async () => { | ||
const element = createTestComponent({ | ||
userActions: exampleActions, | ||
startTimestamp: new Date('2024-09-25T05:07Z'), | ||
}); | ||
await flushPromises(); | ||
|
||
const userActions = element.shadowRoot.querySelectorAll( | ||
selectors.userActions | ||
); | ||
|
||
expect(userActions.length).toBe(exampleActions.length); | ||
for (let index = 0; index < exampleActions.length; index++) { | ||
expect(userActions[index].action).toEqual(exampleActions[index]); | ||
} | ||
}); | ||
}); | ||
}); | ||
|
||
describe('when the user action session contains a ticket creation action', () => { | ||
const exampleActions = [ | ||
{ | ||
actionType: 'SEARCH', | ||
timestamp: new Date('2024-09-25T05:09Z').getTime(), | ||
query: 'example query', | ||
}, | ||
{ | ||
actionType: 'TICKET_CREATION', | ||
timestamp: new Date('2024-09-25T05:08Z').getTime(), | ||
}, | ||
{ | ||
actionType: 'SEARCH', | ||
timestamp: new Date('2024-09-25T05:07Z').getTime(), | ||
query: 'example query', | ||
}, | ||
]; | ||
const numberOfActionsAfterTicketCreation = 1; | ||
|
||
describe('the session start date', () => { | ||
it('should display the session start date with the icon', async () => { | ||
const element = createTestComponent({ | ||
userActions: exampleActions, | ||
startTimestamp: new Date('2024-09-25T05:07Z'), | ||
}); | ||
await flushPromises(); | ||
|
||
const sessionDateIcon = element.shadowRoot.querySelector( | ||
selectors.sessionDateIcon | ||
); | ||
const sessionDate = element.shadowRoot.querySelector( | ||
selectors.sessionDate | ||
); | ||
|
||
expect(sessionDateIcon).not.toBeNull(); | ||
expect(sessionDate).not.toBeNull(); | ||
|
||
expect(sessionDate.textContent).toBe('Wed. September 25, 2024'); | ||
}); | ||
}); | ||
|
||
describe('the session user actions', () => { | ||
it('should display the user actions that occurred before the ticket creation', async () => { | ||
const element = createTestComponent({ | ||
userActions: exampleActions, | ||
startTimestamp: new Date('2024-09-25T05:07Z'), | ||
}); | ||
await flushPromises(); | ||
|
||
const userActions = element.shadowRoot.querySelectorAll( | ||
selectors.userActions | ||
); | ||
|
||
expect(userActions.length).toBe( | ||
exampleActions.length - numberOfActionsAfterTicketCreation | ||
); | ||
for ( | ||
let index = numberOfActionsAfterTicketCreation; | ||
index < exampleActions.length; | ||
index++ | ||
) { | ||
expect(userActions[index - 1].action).toEqual(exampleActions[index]); | ||
} | ||
}); | ||
|
||
it('should not display the user actions that occurred after the ticket creation', async () => { | ||
const element = createTestComponent({ | ||
userActions: exampleActions, | ||
startTimestamp: new Date('2024-09-25T05:07Z'), | ||
}); | ||
await flushPromises(); | ||
|
||
const userActions = element.shadowRoot.querySelectorAll( | ||
selectors.userActionsAferTicketCreation | ||
); | ||
|
||
expect(userActions.length).toBe(0); | ||
}); | ||
|
||
describe('after clicking the show more actions button', () => { | ||
it('should display the user actions that occurred after the ticket creation', async () => { | ||
const element = createTestComponent({ | ||
userActions: exampleActions, | ||
startTimestamp: new Date('2024-09-25T05:07Z'), | ||
}); | ||
await flushPromises(); | ||
|
||
const showMoreActions = element.shadowRoot.querySelector( | ||
selectors.showMoreActions | ||
); | ||
|
||
showMoreActions.click(); | ||
await flushPromises(); | ||
|
||
const userActionsAferTicketCreation = | ||
element.shadowRoot.querySelectorAll( | ||
selectors.userActionsAferTicketCreation | ||
); | ||
|
||
expect(userActionsAferTicketCreation.length).toBe( | ||
numberOfActionsAfterTicketCreation | ||
); | ||
for ( | ||
let index = 0; | ||
index < numberOfActionsAfterTicketCreation; | ||
index++ | ||
) { | ||
expect(userActionsAferTicketCreation[index].action).toEqual( | ||
exampleActions[index] | ||
); | ||
} | ||
}); | ||
}); | ||
}); | ||
|
||
describe('the show more actions button', () => { | ||
it('should display the show more actions button', async () => { | ||
const element = createTestComponent({ | ||
userActions: exampleActions, | ||
startTimestamp: new Date('2024-09-25T05:07Z'), | ||
}); | ||
await flushPromises(); | ||
|
||
const showMoreActions = element.shadowRoot.querySelector( | ||
selectors.showMoreActions | ||
); | ||
|
||
expect(showMoreActions).not.toBeNull(); | ||
}); | ||
|
||
it('should hide the show more actions button after clicking on it', async () => { | ||
const element = createTestComponent({ | ||
userActions: exampleActions, | ||
startTimestamp: new Date('2024-09-25T05:07Z'), | ||
}); | ||
await flushPromises(); | ||
|
||
let showMoreActions = element.shadowRoot.querySelector( | ||
selectors.showMoreActions | ||
); | ||
|
||
showMoreActions.click(); | ||
await flushPromises(); | ||
|
||
showMoreActions = element.shadowRoot.querySelector( | ||
selectors.showMoreActions | ||
); | ||
expect(showMoreActions).toBeNull(); | ||
}); | ||
}); | ||
}); | ||
}); |
22 changes: 22 additions & 0 deletions
22
...uantic/force-app/main/default/lwc/quanticUserActionsSession/quanticUserActionsSession.css
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
.items-center { | ||
align-items: center; | ||
} | ||
|
||
.session-start__icon-container { | ||
background-color: orange; | ||
border-radius: var(--lwc-borderRadiusCircle, 50%); | ||
width: 24px; | ||
height: 24px; | ||
} | ||
|
||
.session__show-more-actions-button { | ||
font-size: 12px; | ||
} | ||
|
||
.session-start__icon { | ||
--slds-c-icon-color-foreground-default: white; | ||
} | ||
|
||
.session-start__date { | ||
font-style: italic; | ||
} |
40 changes: 40 additions & 0 deletions
40
...antic/force-app/main/default/lwc/quanticUserActionsSession/quanticUserActionsSession.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
<template> | ||
<div class="slds-grid items-center slds-var-m-bottom_xx-small"> | ||
<template lwc:if={isTicketCreationSession}> | ||
<div data-test="session-start__date-icon" | ||
class="session-start__icon-container slds-grid slds-grid_align-center slds-var-m-right_x-small items-center"> | ||
<lightning-icon class='session-start__icon' icon-name='utility:priority' | ||
size="xx-small"></lightning-icon> | ||
</div> | ||
</template> | ||
<div data-test="session-start__date" class="session-start__date slds-text-title_bold">{formatedStartDate}</div> | ||
</div> | ||
|
||
<template lwc:if={areActionsAfterTicketCreationVisible}> | ||
<div data-test="session__user-actions-after-ticket-creation" class="slds-var-p-horizontal_xx-smalls"> | ||
<template for:each={userActionsAfterTicketCreation} for:item="action"> | ||
<div key={action.timestamp}> | ||
<c-quantic-user-action action={action}></c-quantic-user-action> | ||
</div> | ||
</template> | ||
</div> | ||
</template> | ||
|
||
<template lwc:if={isShowMoreActionsButtonVisible}> | ||
<div class="slds-var-p-horizontal_xx-smalls"> | ||
<lightning-button data-test="session__show-more-actions-button" class="session__show-more-actions-button" | ||
variant="base" label={showMoreActionsButtonLabel} title={showMoreActionsButtonLabel} | ||
onclick={showActionsAfterTicketCreation} icon-name="utility:threedots"></lightning-button> | ||
</div> | ||
</template> | ||
|
||
|
||
<div data-test="session__user-actions" class="slds-var-p-horizontal_xx-smalls"> | ||
<template for:each={userActionsToDisplay} for:item="action"> | ||
<div key={action.timestamp}> | ||
<c-quantic-user-action action={action}></c-quantic-user-action> | ||
</div> | ||
</template> | ||
</div> | ||
|
||
</template> |
Oops, something went wrong.