diff --git a/public/locales/en.json b/public/locales/en.json index aa8e39d0bc..c63b3c909d 100644 --- a/public/locales/en.json +++ b/public/locales/en.json @@ -711,7 +711,11 @@ "deleteAdvertisement": "Delete Advertisement", "deleteAdvertisementMsg": "Do you want to remove this advertisement?", "no": "No", - "yes": "Yes" + "yes": "Yes", + "view": "View", + "edit": "Edit", + "editAdvertisement": "Edit Advertisement", + "saveChanges": "Save Changes" }, "userChat": { "chat": "Chat", diff --git a/public/locales/fr.json b/public/locales/fr.json index 4b88d8ee24..99444a31b1 100644 --- a/public/locales/fr.json +++ b/public/locales/fr.json @@ -697,7 +697,11 @@ "deleteAdvertisement": "Supprimer l'annonce", "deleteAdvertisementMsg": "Voulez-vous supprimer cette annonce ?", "no": "Non", - "yes": "Oui" + "yes": "Oui", + "view": "Voir", + "edit": "Éditer", + "editAdvertisement": "Éditer l'annonce", + "saveChanges": "Enregistrer les modifications" }, "userChat": { "chat": "Chat", diff --git a/public/locales/hi.json b/public/locales/hi.json index ca6b731fe4..ed73035e91 100644 --- a/public/locales/hi.json +++ b/public/locales/hi.json @@ -697,7 +697,11 @@ "deleteAdvertisement": "विज्ञापन हटाएं", "deleteAdvertisementMsg": "क्या आप इस विज्ञापन को हटाना चाहते हैं?", "no": "नहीं", - "yes": "हाँ" + "yes": "हाँ", + "view": "देखें", + "edit": "संपादित करें", + "editAdvertisement": "विज्ञापन संपादित करें", + "saveChanges": "परिवर्तन सहेजें" }, "userChat": { "chat": "बात", diff --git a/public/locales/sp.json b/public/locales/sp.json index 493efcc364..ec773c8cd9 100644 --- a/public/locales/sp.json +++ b/public/locales/sp.json @@ -697,7 +697,11 @@ "deleteAdvertisement": "Eliminar anuncio", "deleteAdvertisementMsg": "¿Desea eliminar este anuncio?", "no": "No", - "yes": "Sí" + "yes": "Sí", + "view": "Ver", + "edit": "Editar", + "editAdvertisement": "Editar Anuncio", + "saveChanges": "Guardar Cambios" }, "userChat": { "chat": "Charlar", diff --git a/public/locales/zh.json b/public/locales/zh.json index 13be168772..cd778ee3c9 100644 --- a/public/locales/zh.json +++ b/public/locales/zh.json @@ -697,7 +697,11 @@ "deleteAdvertisement": "删除广告", "deleteAdvertisementMsg": "您是否要删除此广告?", "no": "不", - "yes": "是" + "yes": "是", + "view": "查看", + "edit": "编辑", + "editAdvertisement": "编辑广告", + "saveChanges": "保存更改" }, "userChat": { "chat": "聊天", diff --git a/src/GraphQl/Mutations/mutations.ts b/src/GraphQl/Mutations/mutations.ts index 00c6892a8c..a3359833a1 100644 --- a/src/GraphQl/Mutations/mutations.ts +++ b/src/GraphQl/Mutations/mutations.ts @@ -443,6 +443,31 @@ export const ADD_ADVERTISEMENT_MUTATION = gql` } } `; +export const UPDATE_ADVERTISEMENT_MUTATION = gql` + mutation UpdateAdvertisement( + $id: ID! + $name: String + $link: String + $type: AdvertisementType + $startDate: Date + $endDate: Date + ) { + updateAdvertisement( + input: { + _id: $id + name: $name + link: $link + type: $type + startDate: $startDate + endDate: $endDate + } + ) { + advertisement { + _id + } + } + } +`; export const DELETE_ADVERTISEMENT_BY_ID = gql` mutation ($id: ID!) { deleteAdvertisementById(id: $id) { diff --git a/src/components/Advertisements/Advertisements.test.tsx b/src/components/Advertisements/Advertisements.test.tsx index bf97628500..03ce66fb85 100644 --- a/src/components/Advertisements/Advertisements.test.tsx +++ b/src/components/Advertisements/Advertisements.test.tsx @@ -163,57 +163,6 @@ const ORGANIZATIONS_LIST_MOCK = { }; describe('Testing Advertisement Component', () => { - test('Testing if the deletion works', async () => { - const mocks = [ - { - request: { - query: ADVERTISEMENTS_GET, - }, - result: { - data: { - getAdvertisements: [ - { - _id: '1', - name: 'Advertisement1', - type: 'POPUP', - orgId: 'undefined', - link: 'http://example1.com', - endDate: '2023-01-01', - startDate: '2022-01-01', - }, - ], - }, - loading: false, - }, - }, - ORGANIZATIONS_LIST_MOCK, - PLUGIN_GET_MOCK, - ADD_ADVERTISEMENT_MUTATION_MOCK, - ]; - - render( - - - - - - - - - - - ); - - await wait(); - - await act(async () => { - await userEvent.click(screen.getByText('Delete')); - }); - await act(async () => { - await userEvent.click(screen.getByText('Yes')); - }); - }); - test('for creating new Advertisements', async () => { const mocks = [ ORGANIZATIONS_LIST_MOCK, diff --git a/src/components/Advertisements/Advertisements.tsx b/src/components/Advertisements/Advertisements.tsx index 279e0fd3eb..21a0bf0b8b 100644 --- a/src/components/Advertisements/Advertisements.tsx +++ b/src/components/Advertisements/Advertisements.tsx @@ -141,6 +141,7 @@ export default function advertisements(): JSX.Element { orgId={ad.orgId} startDate={new Date(ad.startDate)} endDate={new Date(ad.endDate)} + link={ad.link} // getInstalledPlugins={getInstalledPlugins} /> ) diff --git a/src/components/Advertisements/core/AdvertisementEntry/AdvertisementEntry.module.css b/src/components/Advertisements/core/AdvertisementEntry/AdvertisementEntry.module.css index 1f1ea89996..20bb86a21a 100644 --- a/src/components/Advertisements/core/AdvertisementEntry/AdvertisementEntry.module.css +++ b/src/components/Advertisements/core/AdvertisementEntry/AdvertisementEntry.module.css @@ -4,13 +4,12 @@ } .entryaction { - margin-left: auto; display: flex !important; - align-items: center; } .entryaction i { margin-right: 8px; + margin-top: 4px; } .entryaction .spinner-grow { @@ -18,3 +17,54 @@ width: 1rem; margin-right: 8px; } + +.buttons { + display: flex; + justify-content: flex-end; +} + +.dropdownButton { + background-color: transparent; + color: #000; + border: none; + cursor: pointer; + display: flex; + width: 100%; + justify-content: flex-end; + padding: 8px 10px; +} + +.dropdownContainer { + position: relative; + display: inline-block; +} + +.dropdownmenu { + display: none; + position: absolute; + z-index: 1; + background-color: white; + width: 120px; + box-shadow: 0px 8px 16px 0px rgba(0, 0, 0, 0.2); + padding: 5px 0; + margin: 0; + list-style-type: none; + right: 0; + top: 100%; +} + +.dropdownmenu li { + cursor: pointer; + padding: 8px 16px; + text-decoration: none; + display: block; + color: #333; +} + +.dropdownmenu li:hover { + background-color: #f1f1f1; +} + +.dropdownContainer:hover .dropdownmenu { + display: block; +} diff --git a/src/components/Advertisements/core/AdvertisementEntry/AdvertisementEntry.test.tsx b/src/components/Advertisements/core/AdvertisementEntry/AdvertisementEntry.test.tsx index bedd1c1ce9..5ae43aed5a 100644 --- a/src/components/Advertisements/core/AdvertisementEntry/AdvertisementEntry.test.tsx +++ b/src/components/Advertisements/core/AdvertisementEntry/AdvertisementEntry.test.tsx @@ -1,6 +1,5 @@ import React from 'react'; import { render, fireEvent, waitFor, screen } from '@testing-library/react'; - import { ApolloClient, ApolloProvider, @@ -8,15 +7,16 @@ import { ApolloLink, HttpLink, } from '@apollo/client'; - import type { NormalizedCacheObject } from '@apollo/client'; import { BrowserRouter } from 'react-router-dom'; import AdvertisementEntry from './AdvertisementEntry'; +import AdvertisementRegister from '../AdvertisementRegister/AdvertisementRegister'; import { Provider } from 'react-redux'; import { store } from 'state/store'; import { BACKEND_URL } from 'Constant/constant'; import i18nForTest from 'utils/i18nForTest'; import { I18nextProvider } from 'react-i18next'; +import dayjs from 'dayjs'; const httpLink = new HttpLink({ uri: BACKEND_URL, @@ -24,6 +24,12 @@ const httpLink = new HttpLink({ authorization: 'Bearer ' + localStorage.getItem('token') || '', }, }); +const translations = JSON.parse( + JSON.stringify( + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion, @typescript-eslint/no-non-null-asserted-optional-chain + i18nForTest.getDataByLanguage('en')?.translation.advertisement! + ) +); const client: ApolloClient = new ApolloClient({ cache: new InMemoryCache(), @@ -40,7 +46,7 @@ jest.mock('@apollo/client', () => { }); describe('Testing Advertisement Entry Component', () => { - test('Temporary test for Advertisement Entry', async () => { + test('Testing rendering and deleting of advertisement', async () => { const deleteAdByIdMock = jest.fn(); mockUseMutation.mockReturnValue([deleteAdByIdMock]); const { getByTestId, getAllByText } = render( @@ -48,38 +54,36 @@ describe('Testing Advertisement Entry Component', () => { - { - - } + ); + + //Testing rendering expect(getByTestId('AdEntry')).toBeInTheDocument(); expect(getAllByText('POPUP')[0]).toBeInTheDocument(); expect(getAllByText('Advert1')[0]).toBeInTheDocument(); - fireEvent.click(getByTestId('AddOnEntry_btn_install')); + //Testing successful deletion + fireEvent.click(getByTestId('moreiconbtn')); + fireEvent.click(getByTestId('deletebtn')); await waitFor(() => { expect(screen.getByTestId('delete_title')).toBeInTheDocument(); expect(screen.getByTestId('delete_body')).toBeInTheDocument(); }); - fireEvent.click(getByTestId('AddOnEntry_btn_install')); - - fireEvent.click(getByTestId('AddOnEntry_btn_install')); - fireEvent.click(getByTestId('delete_yes')); await waitFor(() => { @@ -92,9 +96,10 @@ describe('Testing Advertisement Entry Component', () => { expect(deletedMessage).toBeNull(); }); + //Testing unsuccessful deletion deleteAdByIdMock.mockRejectedValueOnce(new Error('Deletion Failed')); - fireEvent.click(getByTestId('AddOnEntry_btn_install')); + fireEvent.click(getByTestId('moreiconbtn')); fireEvent.click(getByTestId('delete_yes')); @@ -113,4 +118,324 @@ describe('Testing Advertisement Entry Component', () => { expect(deletionFailedText).toBeNull(); }); }); + + it('should open and close the dropdown when options button is clicked', () => { + const { getByTestId, queryByText, getAllByText } = render( + + + + + + + + + + ); + + // Test initial rendering + expect(getByTestId('AdEntry')).toBeInTheDocument(); + expect(getAllByText('POPUP')[0]).toBeInTheDocument(); + expect(getAllByText('Advert1')[0]).toBeInTheDocument(); + + // Test dropdown functionality + const optionsButton = getByTestId('moreiconbtn'); + + // Initially, the dropdown should not be visible + expect(queryByText('Edit')).toBeNull(); + + // Click to open the dropdown + fireEvent.click(optionsButton); + + // After clicking the button, the dropdown should be visible + expect(queryByText('Edit')).toBeInTheDocument(); + + // Click again to close the dropdown + fireEvent.click(optionsButton); + + // After the second click, the dropdown should be hidden again + expect(queryByText('Edit')).toBeNull(); + }); + + test('Updates the advertisement and shows success toast on successful update', async () => { + const updateAdByIdMock = jest.fn().mockResolvedValue({ + data: { + updateAdvertisement: { + advertisement: { + _id: '1', + name: 'Updated Advertisement', + link: 'google.com', + startDate: dayjs(new Date()).add(1, 'day').format('YYYY-MM-DD'), + endDate: dayjs(new Date()).add(2, 'days').format('YYYY-MM-DD'), + type: 'BANNER', + }, + }, + }, + }); + + mockUseMutation.mockReturnValue([updateAdByIdMock]); + + render( + + + + + { + + } + + + + + ); + + const optionsButton = screen.getByTestId('moreiconbtn'); + fireEvent.click(optionsButton); + fireEvent.click(screen.getByTestId('editBtn')); + + fireEvent.change(screen.getByLabelText('Enter name of Advertisement'), { + target: { value: 'Updated Advertisement' }, + }); + + expect(screen.getByLabelText('Enter name of Advertisement')).toHaveValue( + 'Updated Advertisement' + ); + + fireEvent.change(screen.getByLabelText(translations.Rlink), { + target: { value: 'http://example.com' }, + }); + expect(screen.getByLabelText(translations.Rlink)).toHaveValue( + 'http://example.com' + ); + + fireEvent.change(screen.getByLabelText(translations.Rtype), { + target: { value: 'BANNER' }, + }); + expect(screen.getByLabelText(translations.Rtype)).toHaveValue('BANNER'); + + fireEvent.change(screen.getByLabelText(translations.RstartDate), { + target: { value: dayjs().add(1, 'day').format('YYYY-MM-DD') }, + }); + + fireEvent.change(screen.getByLabelText(translations.RendDate), { + target: { value: dayjs().add(2, 'days').format('YYYY-MM-DD') }, + }); + + fireEvent.click(screen.getByTestId('addonupdate')); + + expect(updateAdByIdMock).toHaveBeenCalledWith({ + variables: { + id: '1', + name: 'Updated Advertisement', + link: 'http://example.com', + type: 'BANNER', + startDate: dayjs().add(1, 'day').format('YYYY-MM-DD'), + endDate: dayjs().add(2, 'days').format('YYYY-MM-DD'), + }, + }); + }); + + test('Simulating if the mutation doesnt have data variable while updating', async () => { + const updateAdByIdMock = jest.fn().mockResolvedValue({ + updateAdvertisement: { + _id: '1', + name: 'Updated Advertisement', + type: 'BANNER', + }, + }); + + mockUseMutation.mockReturnValue([updateAdByIdMock]); + + render( + + + + + { + + } + + + + + ); + + const optionsButton = screen.getByTestId('moreiconbtn'); + fireEvent.click(optionsButton); + fireEvent.click(screen.getByTestId('editBtn')); + + fireEvent.change(screen.getByLabelText('Enter name of Advertisement'), { + target: { value: 'Updated Advertisement' }, + }); + + expect(screen.getByLabelText('Enter name of Advertisement')).toHaveValue( + 'Updated Advertisement' + ); + + fireEvent.change(screen.getByLabelText(translations.Rtype), { + target: { value: 'BANNER' }, + }); + expect(screen.getByLabelText(translations.Rtype)).toHaveValue('BANNER'); + + fireEvent.click(screen.getByTestId('addonupdate')); + + expect(updateAdByIdMock).toHaveBeenCalledWith({ + variables: { + id: '1', + name: 'Updated Advertisement', + type: 'BANNER', + }, + }); + }); + + test('Updates the advertisement and shows error toast on successful update', async () => { + const updateAdByIdMock = jest.fn(); + + mockUseMutation.mockReturnValue([updateAdByIdMock]); + + render( + + + + + { + + } + + + + + ); + + fireEvent.click(screen.getByTestId('editBtn')); + + fireEvent.change(screen.getByLabelText(translations.Rlink), { + target: { value: 'http://example.com' }, + }); + expect(screen.getByLabelText(translations.Rlink)).toHaveValue( + 'http://example.com' + ); + + fireEvent.click(screen.getByTestId('addonupdate')); + + expect(updateAdByIdMock).toHaveBeenCalledWith({ + variables: { + id: '-100', + link: 'http://example.com', + }, + }); + }); + + test('Simulating if the mutation does not have data variable while registering', async () => { + Object.defineProperty(window, 'location', { + configurable: true, + value: { + reload: jest.fn(), + href: 'https://example.com/page/id=1', + }, + }); + const createAdByIdMock = jest.fn().mockResolvedValue({ + data1: { + createAdvertisement: { + _id: '1', + }, + }, + }); + + mockUseMutation.mockReturnValue([createAdByIdMock]); + + render( + + + + + {} + + + + + ); + + fireEvent.click(screen.getByTestId('createAdvertisement')); + + fireEvent.change(screen.getByLabelText('Enter name of Advertisement'), { + target: { value: 'Updated Advertisement' }, + }); + + expect(screen.getByLabelText('Enter name of Advertisement')).toHaveValue( + 'Updated Advertisement' + ); + + fireEvent.change(screen.getByLabelText(translations.Rlink), { + target: { value: 'http://example.com' }, + }); + expect(screen.getByLabelText(translations.Rlink)).toHaveValue( + 'http://example.com' + ); + + fireEvent.change(screen.getByLabelText(translations.Rtype), { + target: { value: 'BANNER' }, + }); + expect(screen.getByLabelText(translations.Rtype)).toHaveValue('BANNER'); + + fireEvent.change(screen.getByLabelText(translations.RstartDate), { + target: { value: '2023-01-01' }, + }); + expect(screen.getByLabelText(translations.RstartDate)).toHaveValue( + '2023-01-01' + ); + + fireEvent.change(screen.getByLabelText(translations.RendDate), { + target: { value: '2023-02-01' }, + }); + expect(screen.getByLabelText(translations.RendDate)).toHaveValue( + '2023-02-01' + ); + + fireEvent.click(screen.getByTestId('addonregister')); + + expect(createAdByIdMock).toHaveBeenCalledWith({ + variables: { + orgId: '1', + name: 'Updated Advertisement', + link: 'http://example.com', + type: 'BANNER', + startDate: dayjs(new Date('2023-01-01')).format('YYYY-MM-DD'), + endDate: dayjs(new Date('2023-02-01')).format('YYYY-MM-DD'), + }, + }); + }); }); diff --git a/src/components/Advertisements/core/AdvertisementEntry/AdvertisementEntry.tsx b/src/components/Advertisements/core/AdvertisementEntry/AdvertisementEntry.tsx index 3f932ad848..3a19860550 100644 --- a/src/components/Advertisements/core/AdvertisementEntry/AdvertisementEntry.tsx +++ b/src/components/Advertisements/core/AdvertisementEntry/AdvertisementEntry.tsx @@ -6,6 +6,8 @@ import { DELETE_ADVERTISEMENT_BY_ID } from 'GraphQl/Mutations/mutations'; import { useMutation } from '@apollo/client'; import { useTranslation } from 'react-i18next'; import { ADVERTISEMENTS_GET } from 'GraphQl/Queries/Queries'; +import AdvertisementRegister from '../AdvertisementRegister/AdvertisementRegister'; +import MoreVertIcon from '@mui/icons-material/MoreVert'; import { toast } from 'react-toastify'; interface InterfaceAddOnEntryProps { id: string; @@ -29,6 +31,7 @@ function advertisementEntry({ }: InterfaceAddOnEntryProps): JSX.Element { const { t } = useTranslation('translation', { keyPrefix: 'advertisement' }); const [buttonLoading, setButtonLoading] = useState(false); + const [dropdown, setDropdown] = useState(false); const [showDeleteModal, setShowDeleteModal] = useState(false); const [deleteAdById] = useMutation(DELETE_ADVERTISEMENT_BY_ID, { @@ -51,12 +54,43 @@ function advertisementEntry({ setButtonLoading(false); } }; + const handleOptionsClick = (): void => { + setDropdown(!dropdown); + }; return ( <> {Array.from({ length: 1 }).map((_, idx) => ( +
+ + {dropdown && ( +
    +
  • + +
  • +
  • + {t('delete')} +
  • +
+ )} +
{type} - {link} - + {link} +
+ +
diff --git a/src/components/Advertisements/core/AdvertisementRegister/AdvertisementRegister.module.css b/src/components/Advertisements/core/AdvertisementRegister/AdvertisementRegister.module.css index c122d386fa..646311041a 100644 --- a/src/components/Advertisements/core/AdvertisementRegister/AdvertisementRegister.module.css +++ b/src/components/Advertisements/core/AdvertisementRegister/AdvertisementRegister.module.css @@ -4,6 +4,16 @@ align-items: center; } -.modalbtn i { +.modalbtn i, +.button i { margin-right: 8px; } + +.button { + min-width: 102px; +} + +.editHeader { + background-color: #31bb6b; + color: white; +} diff --git a/src/components/Advertisements/core/AdvertisementRegister/AdvertisementRegister.test.tsx b/src/components/Advertisements/core/AdvertisementRegister/AdvertisementRegister.test.tsx index 0c14996307..b0249cc48f 100644 --- a/src/components/Advertisements/core/AdvertisementRegister/AdvertisementRegister.test.tsx +++ b/src/components/Advertisements/core/AdvertisementRegister/AdvertisementRegister.test.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { render, fireEvent, waitFor } from '@testing-library/react'; +import { render, fireEvent, waitFor, screen } from '@testing-library/react'; import { ApolloClient, @@ -48,6 +48,7 @@ const MOCKS = [ data: { createAdvertisement: { _id: '1', + __typename: 'Advertisement', }, }, }, @@ -93,7 +94,7 @@ describe('Testing Advertisement Register Component', () => { }); }); - test('AdvertismentRegister component loads correctly', async () => { + test('AdvertismentRegister component loads correctly in register mode', async () => { const { getByText } = render( @@ -118,6 +119,34 @@ describe('Testing Advertisement Register Component', () => { expect(getByText(translations.addNew)).toBeInTheDocument(); }); }); + + test('AdvertismentRegister component loads correctly in edit mode', async () => { + render( + + + + + { + + } + + + + + ); + await waitFor(() => { + expect(screen.getByTestId('editBtn')).toBeInTheDocument(); + }); + }); + test('Opens and closes modals on button click', async () => { const { getByText, queryByText } = render( @@ -147,6 +176,7 @@ describe('Testing Advertisement Register Component', () => { expect(queryByText(translations.close)).not.toBeInTheDocument(); }); }); + test('Submits the form and shows success toast on successful advertisement creation', async () => { const setTimeoutSpy = jest.spyOn(global, 'setTimeout'); @@ -171,40 +201,41 @@ describe('Testing Advertisement Register Component', () => { ); - await waitFor(() => { - fireEvent.click(getByText(translations.addNew)); - expect(queryByText(translations.RClose)).toBeInTheDocument(); + fireEvent.click(getByText(translations.addNew)); + expect(queryByText(translations.RClose)).toBeInTheDocument(); - fireEvent.change(getByLabelText(translations.Rname), { - target: { value: 'Test Advertisement' }, - }); - expect(getByLabelText(translations.Rname)).toHaveValue( - 'Test Advertisement' - ); + fireEvent.change(getByLabelText(translations.Rname), { + target: { value: 'Test Advertisement' }, + }); + expect(getByLabelText(translations.Rname)).toHaveValue( + 'Test Advertisement' + ); - fireEvent.change(getByLabelText(translations.Rlink), { - target: { value: 'http://example.com' }, - }); - expect(getByLabelText(translations.Rlink)).toHaveValue( - 'http://example.com' - ); + fireEvent.change(getByLabelText(translations.Rlink), { + target: { value: 'http://example.com' }, + }); + expect(getByLabelText(translations.Rlink)).toHaveValue( + 'http://example.com' + ); - fireEvent.change(getByLabelText(translations.Rtype), { - target: { value: 'BANNER' }, - }); - expect(getByLabelText(translations.Rtype)).toHaveValue('BANNER'); + fireEvent.change(getByLabelText(translations.Rtype), { + target: { value: 'BANNER' }, + }); + expect(getByLabelText(translations.Rtype)).toHaveValue('BANNER'); - fireEvent.change(getByLabelText(translations.RstartDate), { - target: { value: '2023-01-01' }, - }); - expect(getByLabelText(translations.RstartDate)).toHaveValue('2023-01-01'); + fireEvent.change(getByLabelText(translations.RstartDate), { + target: { value: '2023-01-01' }, + }); + expect(getByLabelText(translations.RstartDate)).toHaveValue('2023-01-01'); - fireEvent.change(getByLabelText(translations.RendDate), { - target: { value: '2023-02-01' }, - }); - expect(getByLabelText(translations.RendDate)).toHaveValue('2023-02-01'); + fireEvent.change(getByLabelText(translations.RendDate), { + target: { value: '2023-02-01' }, + }); + expect(getByLabelText(translations.RendDate)).toHaveValue('2023-02-01'); - fireEvent.click(getByText(translations.register)); + fireEvent.click(getByText(translations.register)); + await waitFor(() => { + // Assert the success toast and setTimeout expect(toast.success).toBeCalledWith( 'Advertisement created successfully' ); @@ -213,6 +244,7 @@ describe('Testing Advertisement Register Component', () => { expect(queryByText(translations.close)).not.toBeInTheDocument(); }); + test('Logs error to the console and shows error toast when advertisement creation fails', async () => { const { getByText, queryByText } = render( @@ -221,12 +253,12 @@ describe('Testing Advertisement Register Component', () => { { } @@ -235,11 +267,11 @@ describe('Testing Advertisement Register Component', () => { ); - await waitFor(() => { - fireEvent.click(getByText(translations.addNew)); - expect(queryByText(translations.RClose)).toBeInTheDocument(); + fireEvent.click(getByText(translations.addNew)); + expect(queryByText(translations.RClose)).toBeInTheDocument(); - fireEvent.click(getByText(translations.register)); + fireEvent.click(getByText(translations.register)); + await waitFor(() => { expect(toast.error).toBeCalledWith( 'An error occured, could not create new advertisement' ); diff --git a/src/components/Advertisements/core/AdvertisementRegister/AdvertisementRegister.tsx b/src/components/Advertisements/core/AdvertisementRegister/AdvertisementRegister.tsx index ff9391fa7b..44b12b01be 100644 --- a/src/components/Advertisements/core/AdvertisementRegister/AdvertisementRegister.tsx +++ b/src/components/Advertisements/core/AdvertisementRegister/AdvertisementRegister.tsx @@ -1,9 +1,12 @@ -import React, { useState } from 'react'; +import React, { useState, useEffect } from 'react'; import PropTypes from 'prop-types'; import styles from './AdvertisementRegister.module.css'; import { Button, Form, Modal } from 'react-bootstrap'; +import { + ADD_ADVERTISEMENT_MUTATION, + UPDATE_ADVERTISEMENT_MUTATION, +} from 'GraphQl/Mutations/mutations'; import { useMutation, useQuery } from '@apollo/client'; -import { ADD_ADVERTISEMENT_MUTATION } from 'GraphQl/Mutations/mutations'; import { useTranslation } from 'react-i18next'; import { toast } from 'react-toastify'; import dayjs from 'dayjs'; @@ -12,6 +15,14 @@ import { ADVERTISEMENTS_GET } from 'GraphQl/Queries/Queries'; interface InterfaceAddOnRegisterProps { id?: string; // OrgId createdBy?: string; // User + formStatus?: string; + idEdit?: string; + nameEdit?: string; + typeEdit?: string; + orgIdEdit?: string; + linkEdit?: string; + endDateEdit?: Date; + startDateEdit?: Date; } interface InterfaceFormStateTypes { name: string; @@ -25,6 +36,16 @@ interface InterfaceFormStateTypes { function advertisementRegister({ /* eslint-disable-next-line @typescript-eslint/no-unused-vars */ createdBy, + formStatus, + idEdit, + nameEdit, + typeEdit, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + orgIdEdit, + linkEdit, + endDateEdit, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + startDateEdit, }: InterfaceAddOnRegisterProps): JSX.Element { const { t } = useTranslation('translation', { keyPrefix: 'advertisement' }); @@ -33,6 +54,7 @@ function advertisementRegister({ const handleClose = (): void => setShow(false); const handleShow = (): void => setShow(true); const [create] = useMutation(ADD_ADVERTISEMENT_MUTATION); + const [updateAdvertisement] = useMutation(UPDATE_ADVERTISEMENT_MUTATION); const { refetch } = useQuery(ADVERTISEMENTS_GET); //getting orgId from URL @@ -45,6 +67,30 @@ function advertisementRegister({ endDate: new Date(), orgId: currentOrg, }); + + //if set to edit set the formState by edit variables + useEffect(() => { + if (formStatus === 'edit') { + setFormState((prevState) => ({ + ...prevState, + name: nameEdit || '', + link: linkEdit || '', + type: typeEdit || 'BANNER', + startDate: startDateEdit || new Date(), + endDate: endDateEdit || new Date(), + orgId: currentOrg, + })); + } + }, [ + formStatus, + nameEdit, + linkEdit, + typeEdit, + startDateEdit, + endDateEdit, + currentOrg, + ]); + const handleRegister = async (): Promise => { try { console.log('At handle register', formState); @@ -77,20 +123,89 @@ function advertisementRegister({ console.log('error occured', error); } }; + const handleUpdate = async (): Promise => { + try { + const updatedFields: Partial = {}; + + // Only include the fields which are updated + if (formState.name !== nameEdit) { + updatedFields.name = formState.name; + } + if (formState.link !== linkEdit) { + updatedFields.link = formState.link; + } + if (formState.type !== typeEdit) { + updatedFields.type = formState.type; + } + const startDateFormattedString = dayjs(formState.startDate).format( + 'YYYY-MM-DD' + ); + const endDateFormattedString = dayjs(formState.endDate).format( + 'YYYY-MM-DD' + ); + + const startDateDate = dayjs( + startDateFormattedString, + 'YYYY-MM-DD' + ).toDate(); + const endDateDate = dayjs(endDateFormattedString, 'YYYY-MM-DD').toDate(); + + if (!dayjs(startDateDate).isSame(startDateEdit, 'day')) { + updatedFields.startDate = startDateDate; + } + if (!dayjs(endDateDate).isSame(endDateEdit, 'day')) { + updatedFields.endDate = endDateDate; + } + + console.log('At handle update', updatedFields); + const { data } = await updateAdvertisement({ + variables: { + id: idEdit, + ...(updatedFields.name && { name: updatedFields.name }), + ...(updatedFields.link && { link: updatedFields.link }), + ...(updatedFields.type && { type: updatedFields.type }), + ...(updatedFields.startDate && { + startDate: startDateFormattedString, + }), + ...(updatedFields.endDate && { endDate: endDateFormattedString }), + }, + }); + + if (data) { + toast.success('Advertisement updated successfully'); + refetch(); + handleClose(); + } + } catch (error: any) { + toast.error(error.message); + } + }; return ( + //If register show register button else show edit button <> - + {formStatus === 'register' ? ( + + ) : ( +
+ {t('edit')} +
+ )} - - {t('RClose')} + + {formStatus === 'register' ? ( + {t('RClose')} + ) : ( + {t('editAdvertisement')} + )}
@@ -136,7 +251,6 @@ function advertisementRegister({ ...formState, type: e.target.value, }); - console.log(e.target, e.target.value, typeof e.target.value); }} > @@ -149,7 +263,7 @@ function advertisementRegister({ { setFormState({ ...formState, @@ -164,7 +278,7 @@ function advertisementRegister({ { setFormState({ ...formState, @@ -183,13 +297,23 @@ function advertisementRegister({ > {t('close')} - + {formStatus === 'register' ? ( + + ) : ( + + )} @@ -203,6 +327,7 @@ advertisementRegister.defaultProps = { startDate: new Date(), endDate: new Date(), orgId: '', + formStatus: 'register', }; advertisementRegister.propTypes = { @@ -212,6 +337,7 @@ advertisementRegister.propTypes = { startDate: PropTypes.instanceOf(Date), endDate: PropTypes.instanceOf(Date), orgId: PropTypes.string, + formStatus: PropTypes.string, }; export default advertisementRegister;