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(conversation): #WB-3633, services, queries, routing and basic pages of React app #562

Merged
merged 16 commits into from
Jan 6, 2025
9 changes: 9 additions & 0 deletions conversation/frontend/src/config/Actions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { ACTION, IAction } from 'edifice-ts-client';

export const existingActions: IAction[] = [
{
id: ACTION.CREATE,
workflow:
'org.entcore.conversation.controllers.ConversationController|createDraft',
},
];
2 changes: 2 additions & 0 deletions conversation/frontend/src/config/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,5 @@
This folder should contain all config and constants
* * * * * * * * * * * * * * * * * * * * * * * * * * * *
*/

export * from './Actions';
84 changes: 84 additions & 0 deletions conversation/frontend/src/features/app/Action/AppActionHeader.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import { Fragment, RefAttributes } from 'react';

import { Options, Plus, Print } from '@edifice-ui/icons';
import {
Button,
Dropdown,
IconButton,
IconButtonProps,
useOdeClient,
} from '@edifice-ui/react';
import { useTranslation } from 'react-i18next';
import { AppActionMenuOptions } from './AppActionMenuOptions';
import { useAppActions } from '~/store/actions';

export const AppActionHeader = () => {
const { appCode } = useOdeClient();
const { t } = useTranslation(appCode);
const { t: common_t } = useTranslation('common');
const { setOpenPrintModal } = useAppActions();

const dropdownOptions: AppActionMenuOptions[] = [
{
id: 'print',
label: t('print'),
icon: <Print />,
action: () => setOpenPrintModal(true),
visibility: true,
},
];

const handleCreateNewClick = () => {
alert('Create new');
};

return (
<div className="d-flex flex-fill align-items-center justify-content-end gap-12 align-self-end">
<Button
leftIcon={<Plus />}
onClick={handleCreateNewClick}
className="text-nowrap"
>
{t('new.message')}
</Button>

<Dropdown>
{(
triggerProps: JSX.IntrinsicAttributes &
Omit<IconButtonProps, 'ref'> &
RefAttributes<HTMLButtonElement>,
) => (
<div data-testid="dropdown">
<IconButton
{...triggerProps}
type="button"
aria-label={common_t('tiptap.tooltip.plus')}
color="primary"
variant="outline"
icon={<Options />}
/>

<Dropdown.Menu>
{dropdownOptions.map((option) => (
<Fragment key={option.id}>
{option.type === 'divider' ? (
<Dropdown.Separator />
) : (
option.visibility && (
<Dropdown.Item
icon={option.icon}
onClick={() => option.action(null)}
>
{option.label}
</Dropdown.Item>
)
)}
</Fragment>
))}
</Dropdown.Menu>
</div>
)}
</Dropdown>
</div>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { DropdownMenuOptions } from '@edifice-ui/react';

export type AppActionMenuOptions = {
id: string;
visibility: boolean;
} & DropdownMenuOptions;
95 changes: 94 additions & 1 deletion conversation/frontend/src/mocks/handlers.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
import { HttpResponse, http } from 'msw';
import { baseUrl } from '~/services';
import {
mockFolderTree,
mockFullMessage,
mockMessagesOfInbox,
mockSentMessage,
} from '.';

/**
* DO NOT MODIFY
Expand Down Expand Up @@ -229,4 +236,90 @@ const defaultHandlers = [
* MSW Handlers
* Mock HTTP methods for your own application
*/
export const handlers = [...defaultHandlers];
export const handlers = [
...defaultHandlers,
// Folder service
http.get(`${baseUrl}/api/folders`, () => {
return HttpResponse.json(mockFolderTree, { status: 200 });
}),
http.get(`${baseUrl}/api/folders/:folderId/messages`, ({ params }) => {
if (params['folderId'] != 'inbox') {
return HttpResponse.text('Unexpected error', { status: 500 });
} else {
return HttpResponse.json(mockMessagesOfInbox, { status: 200 });
}
}),
http.post(`${baseUrl}/conversation/folder`, () => {
return HttpResponse.json({ id: 'folder_Z' }, { status: 201 });
}),
http.put(`${baseUrl}/conversation/folder/:folderId`, () => {
return HttpResponse.json({}, { status: 200 });
}),
http.put(`${baseUrl}/conversation/folder/trash/:folderId`, () => {
return HttpResponse.json({}, { status: 200 });
}),
// Message service
http.get(`${baseUrl}/api/messages/:messageId`, () => {
return HttpResponse.json(mockFullMessage, { status: 200 });
}),
http.post<
object,
{
id: string[];
unread: boolean;
}
>(`${baseUrl}/conversation/toggleUnread`, async ({ request }) => {
const payload = await request.json();
if (
!payload ||
!Array.isArray(payload.id) ||
typeof payload.unread !== 'boolean'
) {
return HttpResponse.text('Bad Request', { status: 400 });
}
return HttpResponse.text('', { status: 200 });
}),
http.put<
object,
{
id: string[];
}
>(`${baseUrl}/conversation/restore`, async ({ request }) => {
const payload = await request.json();
if (!payload || !Array.isArray(payload.id)) {
return HttpResponse.text('Bad Request', { status: 400 });
}
return HttpResponse.text('', { status: 200 });
}),
http.put<
object,
{
id: string[];
}
>(`${baseUrl}/conversation/delete`, async ({ request }) => {
const payload = await request.json();
if (!payload || !Array.isArray(payload.id)) {
return HttpResponse.text('Bad Request', { status: 400 });
}
return HttpResponse.text('', { status: 200 });
}),
http.post(`${baseUrl}/conversation/draft`, () => {
return HttpResponse.json({ id: 'message_draft' }, { status: 201 });
}),
http.post(`${baseUrl}/conversation/draft/:draftId`, () => {
return HttpResponse.text('', { status: 200 });
}),
http.post(`${baseUrl}/conversation/send`, async ({ request }) => {
const url = new URL(request.url);
const id = url.searchParams.get('id');
const payload = await request.json();
if (!id) {
return HttpResponse.text('Bad Request', {
status: 400,
});
}
return HttpResponse.json(Object.assign({ id }, mockSentMessage, payload), {
status: 200,
});
}),
];
Loading