Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
174 changes: 150 additions & 24 deletions cypress/e2e/player/main.cy.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { AppDataVisibility, Context, PermissionLevel } from '@graasp/sdk';

import type { CommentAppData } from '../../../src/config/appData';
import {
buildCommentContainerDataCy,
buildDataCy,
Expand All @@ -25,6 +26,17 @@ const defaultAppData = [
const MESSAGE_INPUT = 'textarea[name="Message"]';
const SEND_BUTTON = '[name="Send message"]';

const goToConversation = (appData: CommentAppData) => {
const txt = appData.data.content;
cy.contains('tr', txt.slice(0, 10))
.find('button[title="Open conversation"]')
.click();
};

const createConversation = () => {
cy.get('button:contains("New conversation")').click();
};

describe('Player View', () => {
it('Show messages and write a new one', () => {
cy.setUpApi(
Expand All @@ -39,6 +51,9 @@ describe('Player View', () => {
);
cy.visit('/');

// go to conversation
goToConversation(defaultAppData[0]);

// expect previously saved app data
const [previousAppData] = defaultAppData;
cy.get(buildDataCy(buildCommentContainerDataCy(previousAppData.id))).should(
Expand Down Expand Up @@ -76,6 +91,7 @@ describe('Player View', () => {
},
);
cy.visit('/');
createConversation();

// expect cue
cy.get(buildDataCy(buildCommentContainerDataCy('cue'))).should(
Expand All @@ -102,32 +118,33 @@ describe('Player View', () => {
});

it('Show dates', () => {
const appData = [
{
account: CURRENT_MEMBER,
createdAt: '2025-11-18T16:35:22.010Z',
creator: CURRENT_MEMBER,
data: { content: 'A previously saved message' },
id: '0',
item: MOCK_SERVER_ITEM,
type: 'comment',
updatedAt: '2025-11-18T16:35:22.010Z',
visibility: AppDataVisibility.Member,
},
{
account: CURRENT_MEMBER,
createdAt: '2024-11-18T16:35:22.010Z',
creator: CURRENT_MEMBER,
data: { content: 'A previously saved message' },
id: '1',
item: MOCK_SERVER_ITEM,
type: 'comment',
updatedAt: '2025-11-18T16:35:22.010Z',
visibility: AppDataVisibility.Member,
},
];
cy.setUpApi(
{
appData: [
{
account: CURRENT_MEMBER,
createdAt: '2025-11-18T16:35:22.010Z',
creator: CURRENT_MEMBER,
data: { content: 'A previously saved message' },
id: '0',
item: MOCK_SERVER_ITEM,
type: 'comment',
updatedAt: '2025-11-18T16:35:22.010Z',
visibility: AppDataVisibility.Member,
},
{
account: CURRENT_MEMBER,
createdAt: '2024-11-18T16:35:22.010Z',
creator: CURRENT_MEMBER,
data: { content: 'A previously saved message' },
id: '1',
item: MOCK_SERVER_ITEM,
type: 'comment',
updatedAt: '2025-11-18T16:35:22.010Z',
visibility: AppDataVisibility.Member,
},
],
appData,
appSettings: [MOCK_APP_SETTING],
},
{
Expand All @@ -136,6 +153,8 @@ describe('Player View', () => {
},
);
cy.visit('/');
// go to conversation
goToConversation(appData[0]);

// expect dates
cy.get('#root').should('contain', 'November 18, 2024');
Expand All @@ -154,6 +173,7 @@ describe('Player View', () => {
},
);
cy.visit('/');
createConversation();

const [suggestion] = MOCK_APP_SETTING.data.starterSuggestions;

Expand Down Expand Up @@ -187,6 +207,7 @@ describe('Player View', () => {
},
);
cy.visit('/');
createConversation();

// type and send message with enter key
const message = 'My message';
Expand Down Expand Up @@ -216,4 +237,109 @@ describe('Player View', () => {
message1,
);
});

it.only('Show all conversations', () => {
const appData = [
// first conversation
{
account: CURRENT_MEMBER,
createdAt: '2026-11-18T16:35:22.010Z',
creator: CURRENT_MEMBER,
data: {
content: 'My conversation',
conversationId: 'conversation-id-2',
},
id: '12',
item: MOCK_SERVER_ITEM,
type: 'comment',
updatedAt: '2026-11-18T16:35:22.010Z',
visibility: AppDataVisibility.Member,
},
// second, legacy conversation
{
account: CURRENT_MEMBER,
createdAt: '2025-10-18T16:35:22.010Z',
creator: CURRENT_MEMBER,
data: { content: 'A previously saved message' },
id: '0',
item: MOCK_SERVER_ITEM,
type: 'comment',
updatedAt: '2025-11-18T16:35:22.010Z',
visibility: AppDataVisibility.Member,
},
{
account: CURRENT_MEMBER,
createdAt: '2024-01-18T16:35:22.010Z',
creator: CURRENT_MEMBER,
data: { content: 'Another saved message' },
id: '14',
item: MOCK_SERVER_ITEM,
type: 'comment',
updatedAt: '2025-11-18T17:35:22.010Z',
visibility: AppDataVisibility.Member,
},
// third conversation
{
account: CURRENT_MEMBER,
createdAt: '2023-11-18T16:35:22.010Z',
creator: CURRENT_MEMBER,
data: {
content: 'A question I asked',
conversationId: 'conversation-id-1',
},
id: '13',
item: MOCK_SERVER_ITEM,
type: 'comment',
updatedAt: '2023-11-18T16:35:22.010Z',
visibility: AppDataVisibility.Member,
},
];
cy.setUpApi(
{
appData,
appSettings: [MOCK_APP_SETTING],
},
{
context: Context.Player,
permission: PermissionLevel.Write,
},
);
cy.visit('/');

// should show 3 conversations ordered by creation date desc
cy.get('tr').then((rows) => {
expect(rows).to.have.length(3);

expect(rows[0]).to.contain(appData[0].data.content);
// content is cut because it is too long
expect(rows[1]).to.contain(appData[2].data.content.slice(0, 10));
expect(rows[2]).to.contain(appData[3].data.content);
});

// go to first conversation and show one message
goToConversation(appData[0]);
// expect one user message only
cy.get(buildDataCy(buildCommentContainerDataCy(appData[0].id))).should(
'be.visible',
);
cy.get(buildDataCy(buildCommentContainerDataCy(appData[1].id))).should(
'not.exist',
);

// go back to conversations
cy.get('button:contains("Go back to conversations")').click();

// go to second legacy conversation
goToConversation(appData[2]);
// expect one user message only
cy.get(buildDataCy(buildCommentContainerDataCy(appData[1].id))).should(
'be.visible',
);
cy.get(buildDataCy(buildCommentContainerDataCy(appData[2].id))).should(
'be.visible',
);
cy.get(buildDataCy(buildCommentContainerDataCy(appData[3].id))).should(
'not.exist',
);
});
});
7 changes: 6 additions & 1 deletion src/config/appData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,12 @@ export type VisibilityVariants = 'member' | 'item';

export type CommentData = {
content: string;
parent: string | null;
parent?: string | null;
chatbotPromptSettingId?: string;
/**
* Id of the conversation in which the comment belongs to
* Legacy data have an undefined value
*/
conversationId?: string;
};
export type CommentAppData = AppData<CommentData>;
7 changes: 6 additions & 1 deletion src/langs/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,11 @@
"STARTER_SUGGESTION_PLAYER_BUTTON_ARIA_LABEL": "Ask {{suggestion}}",
"SEND_MESSAGE_BUTTON": "Send message",
"EDIT_CHATBOT": "Edit chatbot",
"MESSAGE_INPUT_LABEL": "Message"
"MESSAGE_INPUT_LABEL": "Message",
"List of Conversations": "List of Conversations",
"Conversation Name": "Conversation Name",
"Last Message Date": "Last Message Date",
"Actions": "Actions",
"Open conversation": "Open conversation"
}
}
7 changes: 6 additions & 1 deletion src/langs/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,11 @@
"STARTER_SUGGESTION_PLACEHOLDER": "Écrire une suggestion ici",
"STARTER_SUGGESTION_PLAYER_BUTTON_ARIA_LABEL": "Demander {{suggestion}}",
"EDIT_CHATBOT": "Modifier le chatbot",
"MESSAGE_INPUT_LABEL": "Message"
"MESSAGE_INPUT_LABEL": "Message",
"List of Conversations": "Liste des discussions",
"Conversation Name": "Nom de la discussion",
"Last Message Date": "Date du dernier message",
"Actions": "Actions",
"Open conversation": "Ouvrir la discussion"
}
}
32 changes: 21 additions & 11 deletions src/modules/analytics/FrequentWords.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,14 @@ function FrequentWords({

const [selectedCustomWords, setSelectedCustomWords] = useState<string[]>([]);
const [customWord, setCustomWord] = useState('');
const [chatMemberID, setChatMemberID] = useState('');
const [selectedConversation, setSelectedConversation] = useState<null | {
accountId: string;
conversationId?: string;
}>(null);

const closeConversation = () => {
setSelectedConversation(null);
};

const isAllSelected = mostFrequentWords.every(
(ele) => -1 < selectedFrequentWords.indexOf(ele),
Expand Down Expand Up @@ -136,7 +143,12 @@ function FrequentWords({
sentence={ele.data.content}
memberName={ele.account.name}
words={[...selectedFrequentWords, ...selectedCustomWords]}
onClick={() => setChatMemberID(ele.account.id)}
onClick={() =>
setSelectedConversation({
accountId: ele.account.id,
conversationId: ele.data.conversationId,
})
}
buttonId={buildCheckWholeMemberChatButtonId(ele.account.id)}
/>
))}
Expand All @@ -148,19 +160,17 @@ function FrequentWords({
)
}
</Stack>
{chatMemberID && (
<Dialog
open
onClose={() => {
setChatMemberID('');
}}
>
{selectedConversation && (
<Dialog open onClose={closeConversation}>
<DialogTitle>{t('ANALYTICS_CONVERSATION_MEMBER')}</DialogTitle>
<DialogContent>
<ConversationForUser accountId={chatMemberID} />
<ConversationForUser
accountId={selectedConversation.accountId}
conversationId={selectedConversation.conversationId}
/>
</DialogContent>
<DialogActions>
<Button>{t('CLOSE')}</Button>
<Button onClick={closeConversation}>{t('CLOSE')}</Button>
</DialogActions>
</Dialog>
)}
Expand Down
28 changes: 28 additions & 0 deletions src/modules/comment/ChatbotContainer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { ReactNode } from 'react';

import { Stack, styled } from '@mui/material';

import { BIG_BORDER_RADIUS } from '@/constants';

const StyledContainer = styled('div')(({ theme }) => ({
backgroundColor: 'white',
border: 'solid silver 1px',
padding: theme.spacing(3, 0),
borderRadius: BIG_BORDER_RADIUS,
}));

export const ChatbotContainer = ({ children }: { children: ReactNode }) => {
return (
<Stack
sx={{
px: { xs: 2, sm: 10 },
maxWidth: '100ch',
m: 'auto',
height: '100%',
}}
gap={2}
>
<StyledContainer>{children}</StyledContainer>
</Stack>
);
};
Loading