From 6a4eedeffb15a8a3bd4312f2313578977e01907d Mon Sep 17 00:00:00 2001 From: Amaan ali Date: Fri, 24 Jan 2025 17:08:07 +0530 Subject: [PATCH 1/2] Addition test cases added to improve code coverage (#3407) --- .../MemberDetail/MemberDetail.spec.tsx | 25 +++++++++++++---- src/screens/MemberDetail/MemberDetail.tsx | 28 ++++++------------- 2 files changed, 28 insertions(+), 25 deletions(-) diff --git a/src/screens/MemberDetail/MemberDetail.spec.tsx b/src/screens/MemberDetail/MemberDetail.spec.tsx index 4c1a68369f..f575fda4fe 100644 --- a/src/screens/MemberDetail/MemberDetail.spec.tsx +++ b/src/screens/MemberDetail/MemberDetail.spec.tsx @@ -104,19 +104,13 @@ describe('MemberDetail', () => { test('should render the elements', async () => { renderMemberDetailScreen(link1); - await wait(); expect(screen.queryByText('Loading data...')).not.toBeInTheDocument(); expect(screen.getAllByText(/Email/i)).toBeTruthy(); expect(screen.getAllByText(/First name/i)).toBeTruthy(); expect(screen.getAllByText(/Last name/i)).toBeTruthy(); - // expect(screen.getAllByText(/Language/i)).toBeTruthy(); - // expect(screen.getByText(/Plugin creation allowed/i)).toBeInTheDocument(); - // expect(screen.getAllByText(/Joined on/i)).toBeTruthy(); - // expect(screen.getAllByText(/Joined On/i)).toHaveLength(1); expect(screen.getAllByText(/Profile Details/i)).toHaveLength(1); - // expect(screen.getAllByText(/Actions/i)).toHaveLength(1); expect(screen.getAllByText(/Contact Information/i)).toHaveLength(1); expect(screen.getAllByText(/Events Attended/i)).toHaveLength(2); }); @@ -255,6 +249,25 @@ describe('MemberDetail', () => { expect(userImage.getAttribute('src')).toBe(user?.image); }); + test('image upload and display works correctly', async () => { + renderMemberDetailScreen(link2); + + await waitFor(() => { + expect(screen.getByTestId('organisationImage')).toBeInTheDocument(); + }); + const file = new File(['hello'], 'hello.png', { type: 'image/png' }); + const fileInput = screen.getByTestId( + 'organisationImage', + ) as HTMLInputElement; + fireEvent.change(fileInput, { target: { files: [file] } }); + + await waitFor(() => { + const userImage = screen.getByTestId('userImagePresent'); + expect(userImage).toBeInTheDocument(); + expect(userImage.getAttribute('src')).toContain('data:image/png;base64'); + }); + }); + test('resetChangesBtn works properly', async () => { renderMemberDetailScreen(link1); diff --git a/src/screens/MemberDetail/MemberDetail.tsx b/src/screens/MemberDetail/MemberDetail.tsx index cc528a8de3..fd7fcd48e4 100644 --- a/src/screens/MemberDetail/MemberDetail.tsx +++ b/src/screens/MemberDetail/MemberDetail.tsx @@ -42,8 +42,7 @@ type MemberDetailProps = { /** * MemberDetail component is used to display the details of a user. * It also allows the user to update the details. It uses the UPDATE_USER_MUTATION to update the user details. - * It uses the USER_DETAILS query to get the user details. It uses the useLocalStorage hook to store the user - * details in the local storage. + * It uses the USER_DETAILS query to get the user details. It uses the useLocalStorage hook to store the user details in the local storage. * @param id - The id of the user whose details are to be displayed. * @returns React component * @@ -87,6 +86,7 @@ const MemberDetail: React.FC = ({ id }): JSX.Element => { }); const handleDateChange = (date: Dayjs | null): void => { if (date) { + console.log('formated', dayjs(date).format('YYYY-MM-DD')); setisUpdated(true); setFormState((prevState) => ({ ...prevState, @@ -95,7 +95,6 @@ const MemberDetail: React.FC = ({ id }): JSX.Element => { } }; - /*istanbul ignore next*/ const handleEditIconClick = (): void => { fileInputRef.current?.click(); }; @@ -143,19 +142,16 @@ const MemberDetail: React.FC = ({ id }): JSX.Element => { const tagsAssigned = userData?.user?.tagsAssignedWith.edges.map( (edge: { node: InterfaceTagData; cursor: string }) => edge.node, - ) ?? /* istanbul ignore next */ []; + ) ?? []; const loadMoreAssignedTags = (): void => { fetchMoreAssignedTags({ variables: { first: TAGS_QUERY_DATA_CHUNK_SIZE, - after: - user?.user?.user?.tagsAssignedWith?.pageInfo?.endCursor ?? - /* istanbul ignore next */ - null, + after: user?.user?.user?.tagsAssignedWith?.pageInfo?.endCursor ?? null, }, updateQuery: (prevResult, { fetchMoreResult }) => { - if (!fetchMoreResult) /* istanbul ignore next */ return prevResult; + if (!fetchMoreResult) return prevResult; return { user: { @@ -193,7 +189,6 @@ const MemberDetail: React.FC = ({ id }): JSX.Element => { toggleUnassignUserTagModal(); toast.success(t('successfullyUnassigned')); } catch (error: unknown) { - /* istanbul ignore next */ if (error instanceof Error) { toast.error(error.message); } @@ -211,7 +206,6 @@ const MemberDetail: React.FC = ({ id }): JSX.Element => { e: React.ChangeEvent, ): Promise => { const { name, value } = e.target; - /*istanbul ignore next*/ if ( name === 'photo' && 'files' in e.target && @@ -251,7 +245,6 @@ const MemberDetail: React.FC = ({ id }): JSX.Element => { ...formState, }, }); - /* istanbul ignore next */ if (data) { setisUpdated(false); if (getItem('id') === currentUrl) { @@ -264,18 +257,17 @@ const MemberDetail: React.FC = ({ id }): JSX.Element => { } } catch (error: unknown) { if (error instanceof Error) { + console.log('the error is ', error.message); errorHandler(t, error); } } } catch (error: unknown) { - /* istanbul ignore next */ if (error instanceof Error) { errorHandler(t, error); } } }; const resetChanges = (): void => { - /*istanbul ignore next*/ setFormState({ firstName: userData?.user?.firstName || '', lastName: userData?.user?.lastName || '', @@ -351,9 +343,8 @@ const MemberDetail: React.FC = ({ id }): JSX.Element => { role="button" aria-label="Edit profile picture" tabIndex={0} - onKeyDown={ - /*istanbul ignore next*/ - (e) => e.key === 'Enter' && handleEditIconClick() + onKeyDown={(e) => + e.key === 'Enter' && handleEditIconClick() } /> @@ -416,7 +407,7 @@ const MemberDetail: React.FC = ({ id }): JSX.Element => { placeholder={tCommon('lastName')} /> - + @@ -633,7 +624,6 @@ const MemberDetail: React.FC = ({ id }): JSX.Element => { next={loadMoreAssignedTags} hasMore={ userData?.user?.tagsAssignedWith.pageInfo.hasNextPage ?? - /* istanbul ignore next */ false } loader={} From dacdabcbad32eb1b61f5825f7f5aa42fe74738b3 Mon Sep 17 00:00:00 2001 From: Aadhil Ahamed Date: Sat, 25 Jan 2025 00:41:45 +0530 Subject: [PATCH 2/2] Refactored Events Dashboard / Detail Screens (#3390) * Figma Refactoring * CSS changes * fix prettier error --- .../EventManagement/functions/default.md | 2 +- .../Requests/Requests/functions/default.md | 2 +- .../VolunteerGroups/functions/default.md | 2 +- .../Volunteers/functions/default.md | 2 +- .../MemberDetail/functions/default.md | 5 +- .../MemberDetail/functions/getLanguageName.md | 2 +- .../MemberDetail/functions/prettyDate.md | 2 +- public/images/svg/attendees.svg | 6 +- public/images/svg/feedback.svg | 6 +- public/images/svg/options-outline.svg | 8 +- public/images/svg/organization.svg | 6 +- .../CheckIn/CheckInWrapper.spec.tsx | 30 +++ src/components/CheckIn/CheckInWrapper.tsx | 2 +- .../EventAttendance/EventAttendance.spec.tsx | 72 ++++++ .../EventAttendance/EventAttendance.tsx | 35 ++- .../EventRegistrant/EventRegistrants.spec.tsx | 71 ++++++ .../EventRegistrant/EventRegistrants.tsx | 20 +- .../EventManagement/EventManagement.tsx | 219 ++++++++---------- .../Requests/Requests.spec.tsx | 55 ++++- .../EventVolunteers/Requests/Requests.tsx | 39 +++- .../EventVolunteers/VolunteerContainer.tsx | 7 +- .../VolunteerGroups/VolunteerGroups.tsx | 35 +-- .../EventVolunteers/Volunteers/Volunteers.tsx | 32 ++- .../OrganizationActionItems.spec.tsx | 34 +++ .../OrganizationActionItems.tsx | 39 ++-- src/style/app.module.css | 169 ++++++++++---- 26 files changed, 626 insertions(+), 276 deletions(-) diff --git a/docs/docs/auto-docs/screens/EventManagement/EventManagement/functions/default.md b/docs/docs/auto-docs/screens/EventManagement/EventManagement/functions/default.md index c3ebddbbe5..c856506bfe 100644 --- a/docs/docs/auto-docs/screens/EventManagement/EventManagement/functions/default.md +++ b/docs/docs/auto-docs/screens/EventManagement/EventManagement/functions/default.md @@ -6,7 +6,7 @@ > **default**(): `Element` -Defined in: [src/screens/EventManagement/EventManagement.tsx:91](https://github.com/PalisadoesFoundation/talawa-admin/blob/main/src/screens/EventManagement/EventManagement.tsx#L91) +Defined in: [src/screens/EventManagement/EventManagement.tsx:60](https://github.com/PalisadoesFoundation/talawa-admin/blob/main/src/screens/EventManagement/EventManagement.tsx#L60) `EventManagement` component handles the display and navigation of different event management sections. diff --git a/docs/docs/auto-docs/screens/EventVolunteers/Requests/Requests/functions/default.md b/docs/docs/auto-docs/screens/EventVolunteers/Requests/Requests/functions/default.md index dfe1df6c20..4882b8710a 100644 --- a/docs/docs/auto-docs/screens/EventVolunteers/Requests/Requests/functions/default.md +++ b/docs/docs/auto-docs/screens/EventVolunteers/Requests/Requests/functions/default.md @@ -6,7 +6,7 @@ > **default**(): `JSX.Element` -Defined in: [src/screens/EventVolunteers/Requests/Requests.tsx:53](https://github.com/PalisadoesFoundation/talawa-admin/blob/main/src/screens/EventVolunteers/Requests/Requests.tsx#L53) +Defined in: [src/screens/EventVolunteers/Requests/Requests.tsx:64](https://github.com/PalisadoesFoundation/talawa-admin/blob/main/src/screens/EventVolunteers/Requests/Requests.tsx#L64) Component for managing and displaying Volunteer Membership requests for an event. diff --git a/docs/docs/auto-docs/screens/EventVolunteers/VolunteerGroups/VolunteerGroups/functions/default.md b/docs/docs/auto-docs/screens/EventVolunteers/VolunteerGroups/VolunteerGroups/functions/default.md index 443a2be39a..0f10f9cd48 100644 --- a/docs/docs/auto-docs/screens/EventVolunteers/VolunteerGroups/VolunteerGroups/functions/default.md +++ b/docs/docs/auto-docs/screens/EventVolunteers/VolunteerGroups/VolunteerGroups/functions/default.md @@ -6,7 +6,7 @@ > **default**(): `JSX.Element` -Defined in: [src/screens/EventVolunteers/VolunteerGroups/VolunteerGroups.tsx:58](https://github.com/PalisadoesFoundation/talawa-admin/blob/main/src/screens/EventVolunteers/VolunteerGroups/VolunteerGroups.tsx#L58) +Defined in: [src/screens/EventVolunteers/VolunteerGroups/VolunteerGroups.tsx:69](https://github.com/PalisadoesFoundation/talawa-admin/blob/main/src/screens/EventVolunteers/VolunteerGroups/VolunteerGroups.tsx#L69) Component for managing volunteer groups for an event. This component allows users to view, filter, sort, and create action items. It also provides a modal for creating and editing action items. diff --git a/docs/docs/auto-docs/screens/EventVolunteers/Volunteers/Volunteers/functions/default.md b/docs/docs/auto-docs/screens/EventVolunteers/Volunteers/Volunteers/functions/default.md index fddd2b6d7a..5fc651a95e 100644 --- a/docs/docs/auto-docs/screens/EventVolunteers/Volunteers/Volunteers/functions/default.md +++ b/docs/docs/auto-docs/screens/EventVolunteers/Volunteers/Volunteers/functions/default.md @@ -6,7 +6,7 @@ > **default**(): `JSX.Element` -Defined in: [src/screens/EventVolunteers/Volunteers/Volunteers.tsx:65](https://github.com/PalisadoesFoundation/talawa-admin/blob/main/src/screens/EventVolunteers/Volunteers/Volunteers.tsx#L65) +Defined in: [src/screens/EventVolunteers/Volunteers/Volunteers.tsx:76](https://github.com/PalisadoesFoundation/talawa-admin/blob/main/src/screens/EventVolunteers/Volunteers/Volunteers.tsx#L76) Component for managing and displaying event volunteers related to an event. diff --git a/docs/docs/auto-docs/screens/MemberDetail/MemberDetail/functions/default.md b/docs/docs/auto-docs/screens/MemberDetail/MemberDetail/functions/default.md index b1850d81d7..07808da20e 100644 --- a/docs/docs/auto-docs/screens/MemberDetail/MemberDetail/functions/default.md +++ b/docs/docs/auto-docs/screens/MemberDetail/MemberDetail/functions/default.md @@ -6,12 +6,11 @@ > **default**(`props`, `deprecatedLegacyContext`?): `ReactNode` -Defined in: [src/screens/MemberDetail/MemberDetail.tsx:51](https://github.com/PalisadoesFoundation/talawa-admin/blob/main/src/screens/MemberDetail/MemberDetail.tsx#L51) +Defined in: [src/screens/MemberDetail/MemberDetail.tsx:50](https://github.com/PalisadoesFoundation/talawa-admin/blob/main/src/screens/MemberDetail/MemberDetail.tsx#L50) MemberDetail component is used to display the details of a user. It also allows the user to update the details. It uses the UPDATE_USER_MUTATION to update the user details. -It uses the USER_DETAILS query to get the user details. It uses the useLocalStorage hook to store the user - details in the local storage. +It uses the USER_DETAILS query to get the user details. It uses the useLocalStorage hook to store the user details in the local storage. ## Parameters diff --git a/docs/docs/auto-docs/screens/MemberDetail/MemberDetail/functions/getLanguageName.md b/docs/docs/auto-docs/screens/MemberDetail/MemberDetail/functions/getLanguageName.md index 8a27bbbc45..5d161cd446 100644 --- a/docs/docs/auto-docs/screens/MemberDetail/MemberDetail/functions/getLanguageName.md +++ b/docs/docs/auto-docs/screens/MemberDetail/MemberDetail/functions/getLanguageName.md @@ -6,7 +6,7 @@ > **getLanguageName**(`code`): `string` -Defined in: [src/screens/MemberDetail/MemberDetail.tsx:752](https://github.com/PalisadoesFoundation/talawa-admin/blob/main/src/screens/MemberDetail/MemberDetail.tsx#L752) +Defined in: [src/screens/MemberDetail/MemberDetail.tsx:742](https://github.com/PalisadoesFoundation/talawa-admin/blob/main/src/screens/MemberDetail/MemberDetail.tsx#L742) ## Parameters diff --git a/docs/docs/auto-docs/screens/MemberDetail/MemberDetail/functions/prettyDate.md b/docs/docs/auto-docs/screens/MemberDetail/MemberDetail/functions/prettyDate.md index 052e79fb72..01d7d085e0 100644 --- a/docs/docs/auto-docs/screens/MemberDetail/MemberDetail/functions/prettyDate.md +++ b/docs/docs/auto-docs/screens/MemberDetail/MemberDetail/functions/prettyDate.md @@ -6,7 +6,7 @@ > **prettyDate**(`param`): `string` -Defined in: [src/screens/MemberDetail/MemberDetail.tsx:742](https://github.com/PalisadoesFoundation/talawa-admin/blob/main/src/screens/MemberDetail/MemberDetail.tsx#L742) +Defined in: [src/screens/MemberDetail/MemberDetail.tsx:732](https://github.com/PalisadoesFoundation/talawa-admin/blob/main/src/screens/MemberDetail/MemberDetail.tsx#L732) ## Parameters diff --git a/public/images/svg/attendees.svg b/public/images/svg/attendees.svg index 3864a85b7e..011c5565f7 100644 --- a/public/images/svg/attendees.svg +++ b/public/images/svg/attendees.svg @@ -1,4 +1,4 @@ - - - + + + diff --git a/public/images/svg/feedback.svg b/public/images/svg/feedback.svg index 649e84a1c9..79097cbc35 100644 --- a/public/images/svg/feedback.svg +++ b/public/images/svg/feedback.svg @@ -1,5 +1,5 @@ - - - + + + diff --git a/public/images/svg/options-outline.svg b/public/images/svg/options-outline.svg index 939935eb11..a2650b54bb 100644 --- a/public/images/svg/options-outline.svg +++ b/public/images/svg/options-outline.svg @@ -4,8 +4,8 @@ viewBox="0 0 31 32" fill="none" xmlns="http://www.w3.org/2000/svg"> - - - - + + + + diff --git a/public/images/svg/organization.svg b/public/images/svg/organization.svg index 9bed28f87e..74f6d9df5d 100644 --- a/public/images/svg/organization.svg +++ b/public/images/svg/organization.svg @@ -5,12 +5,12 @@ fill="none" xmlns="http://www.w3.org/2000/svg"> - - + + - + \ No newline at end of file diff --git a/src/components/CheckIn/CheckInWrapper.spec.tsx b/src/components/CheckIn/CheckInWrapper.spec.tsx index 06b2695f88..bbbba27ac0 100644 --- a/src/components/CheckIn/CheckInWrapper.spec.tsx +++ b/src/components/CheckIn/CheckInWrapper.spec.tsx @@ -66,3 +66,33 @@ describe('Testing CheckIn Wrapper', () => { ); }); }); + +describe('CheckInWrapper CSS Tests', () => { + const props = { + eventId: 'event123', + }; + + const renderComponent = (): ReturnType => { + return render( + + + + + + + + + + + , + ); + }; + + it('should render the options-outline SVG image with correct dimensions', () => { + renderComponent(); + const image = screen.getByAltText('Sort'); + expect(image).toHaveAttribute('src', '/images/svg/options-outline.svg'); + expect(image).toHaveAttribute('width', '30.63'); + expect(image).toHaveAttribute('height', '30.63'); + }); +}); diff --git a/src/components/CheckIn/CheckInWrapper.tsx b/src/components/CheckIn/CheckInWrapper.tsx index 7b35ce1483..15a68709fa 100644 --- a/src/components/CheckIn/CheckInWrapper.tsx +++ b/src/components/CheckIn/CheckInWrapper.tsx @@ -21,7 +21,7 @@ export const CheckInWrapper = ({ eventId }: PropType): JSX.Element => { <>
-
+
searchEventAttendees(e.target.value)} /> -
- + @@ -248,7 +246,7 @@ function EventAttendance(): JSX.Element { {filteredAttendees.length === 0 ? ( - + {t('noAttendees')} @@ -318,8 +316,7 @@ function EventAttendance(): JSX.Element { {member.eventsAttended ? member.eventsAttended.length - : /*istanbul ignore next*/ - '0'} + : '0'} @@ -328,9 +325,7 @@ function EventAttendance(): JSX.Element { data-testid={`attendee-task-assigned-${index}`} > {member.tagsAssignedWith ? ( - /*istanbul ignore next*/ member.tagsAssignedWith.edges.map( - /*istanbul ignore next*/ ( edge: { node: { name: string } }, tagIndex: number, diff --git a/src/components/EventManagement/EventRegistrant/EventRegistrants.spec.tsx b/src/components/EventManagement/EventRegistrant/EventRegistrants.spec.tsx index 828362706a..c12cdb45ec 100644 --- a/src/components/EventManagement/EventRegistrant/EventRegistrants.spec.tsx +++ b/src/components/EventManagement/EventRegistrant/EventRegistrants.spec.tsx @@ -13,6 +13,7 @@ import { REGISTRANTS_MOCKS } from './Registrations.mocks'; import { MOCKS as ATTENDEES_MOCKS } from '../EventAttendance/Attendance.mocks'; import { vi } from 'vitest'; import { EVENT_REGISTRANTS, EVENT_ATTENDEES } from 'GraphQl/Queries/Queries'; +import styles from '../../../style/app.module.css'; const COMBINED_MOCKS = [...REGISTRANTS_MOCKS, ...ATTENDEES_MOCKS]; @@ -262,3 +263,73 @@ describe('Event Registrants Component', () => { ); }); }); + +describe('EventRegistrants CSS Tests', () => { + const renderEventRegistrants = (): RenderResult => { + return render( + + + + + + + + + , + ); + }; + + beforeEach(() => { + vi.mock('react-router-dom', async () => ({ + ...(await vi.importActual('react-router-dom')), + useParams: () => ({ eventId: 'event123', orgId: 'org123' }), + })); + }); + + afterEach(() => { + vi.clearAllMocks(); + }); + + it('should apply correct styles to the filter button', () => { + renderEventRegistrants(); + const filterButton = screen.getByTestId('filter-button'); + + expect(filterButton).toHaveClass('border-1', 'mx-4', styles.createButton); + }); + + it('should apply correct styles to the table container', () => { + renderEventRegistrants(); + const tableContainer = screen.getByRole('grid').closest('.MuiPaper-root'); + expect(tableContainer).toHaveClass('mt-3'); + expect(tableContainer).toHaveStyle({ + borderRadius: '16px', + }); + }); + + it('should style table header cells with custom cell class', () => { + renderEventRegistrants(); + const headerCells = [ + screen.getByTestId('table-header-serial'), + screen.getByTestId('table-header-registrant'), + screen.getByTestId('table-header-registered-at'), + screen.getByTestId('table-header-created-at'), + screen.getByTestId('table-header-add-registrant'), + ]; + headerCells.forEach((cell) => { + expect(cell).toHaveClass(styles.customcell); + }); + }); + + it('should style the check-in wrapper component correctly', () => { + renderEventRegistrants(); + const checkInWrapper = screen.getByTestId('stats-modal'); + expect(checkInWrapper).toBeInTheDocument(); + expect(checkInWrapper).toHaveClass(styles.createButton); + }); + + it('should apply proper spacing between buttons', () => { + renderEventRegistrants(); + const filterButton = screen.getByTestId('filter-button'); + expect(filterButton).toHaveClass('mx-4'); + }); +}); diff --git a/src/components/EventManagement/EventRegistrant/EventRegistrants.tsx b/src/components/EventManagement/EventRegistrant/EventRegistrants.tsx index d6488025ac..4a5c88e46e 100644 --- a/src/components/EventManagement/EventRegistrant/EventRegistrants.tsx +++ b/src/components/EventManagement/EventRegistrant/EventRegistrants.tsx @@ -123,13 +123,17 @@ function EventRegistrants(): JSX.Element { {t('allRegistrants')} - +
- + @@ -137,25 +141,25 @@ function EventRegistrants(): JSX.Element { {t('registrant')} {t('registeredAt')} {t('createdAt')} {t('addRegistrant')} @@ -163,7 +167,7 @@ function EventRegistrants(): JSX.Element { {combinedData.length === 0 ? ( - + , - }, - { - value: 'registrants', - icon: , - }, - { - value: 'attendance', - icon: , - }, - { - value: 'agendas', - icon: , - }, - { - value: 'actions', - icon: , - }, - { - value: 'volunteers', - icon: , - }, - { - value: 'statistics', - icon: , - }, -]; /** * Tab options for the event management component. @@ -69,6 +32,12 @@ type TabOptions = | 'volunteers' | 'statistics'; +interface InterfaceTabConfig { + value: TabOptions; + icon: JSX.Element; + component: JSX.Element; +} + /** * `EventManagement` component handles the display and navigation of different event management sections. * @@ -97,14 +66,11 @@ const EventManagement = (): JSX.Element => { // Custom hook for accessing local storage const { getItem } = useLocalStorage(); - // Determine user role based on local storage - const superAdmin = getItem('SuperAdmin'); - const adminFor = getItem('AdminFor'); - const userRole = superAdmin - ? 'SUPERADMIN' - : adminFor?.length > 0 - ? 'ADMIN' - : 'USER'; + // Hook for navigation + const navigate = useNavigate(); + + // State hook for managing the currently selected tab + const [tab, setTab] = useState('dashboard'); // Extract event and organization IDs from URL parameters const { eventId, orgId } = useParams(); @@ -113,11 +79,83 @@ const EventManagement = (): JSX.Element => { return ; } - // Hook for navigation - const navigate = useNavigate(); + // Determine user role based on local storage + const superAdmin = getItem('SuperAdmin'); + const adminFor = getItem('AdminFor'); + const userRole = superAdmin + ? 'SUPERADMIN' + : adminFor?.length > 0 + ? 'ADMIN' + : 'USER'; - // State hook for managing the currently selected tab - const [tab, setTab] = useState('dashboard'); + /** + * List of tabs for the event dashboard. + * + * Each tab is associated with an icon, value, and its corresponding component. + */ + const eventDashboardTabs: InterfaceTabConfig[] = [ + { + value: 'dashboard', + icon: , + component: ( +
+ +
+ ), + }, + { + value: 'registrants', + icon: , + component: ( +
+ +
+ ), + }, + { + value: 'attendance', + icon: , + component: ( +
+ +
+ ), + }, + { + value: 'agendas', + icon: , + component: ( +
+ +
+ ), + }, + { + value: 'actions', + icon: , + component: ( +
+ +
+ ), + }, + { + value: 'volunteers', + icon: , + component: ( +
+ +
+ ), + }, + { + value: 'statistics', + icon: , + component: ( +
+ ), + }, + ]; /** * Renders a button for each tab with the appropriate icon and label. @@ -126,20 +164,14 @@ const EventManagement = (): JSX.Element => { * @param icon - The icon to display for the tab * @returns JSX.Element - The rendered button component */ - const renderButton = ({ - value, - icon, - }: { - value: TabOptions; - icon: React.ReactNode; - }): JSX.Element => { + const renderButton = ({ value, icon }: InterfaceTabConfig): JSX.Element => { const selected = tab === value; const variant = selected ? 'success' : 'light'; const translatedText = t(value); const className = selected - ? 'px-4 d-flex align-items-center rounded-3 shadow-sm' - : 'text-secondary bg-white px-4 d-flex align-items-center rounded-3 shadow-sm'; + ? `px-4 d-flex align-items-center rounded-3 shadow-sm ${styles.eventManagementSelectedBtn}` + : `text-secondary bg-white px-4 d-flex align-items-center rounded-3 shadow-sm ${styles.eventManagementBtn}`; const props = { variant, className, @@ -164,15 +196,17 @@ const EventManagement = (): JSX.Element => { } }; + const currentTab = eventDashboardTabs.find((t) => t.value === tab); + return ( -
+
); }; + export default EventManagement; diff --git a/src/screens/EventVolunteers/Requests/Requests.spec.tsx b/src/screens/EventVolunteers/Requests/Requests.spec.tsx index e51e28ab3f..5bd33cc2c8 100644 --- a/src/screens/EventVolunteers/Requests/Requests.spec.tsx +++ b/src/screens/EventVolunteers/Requests/Requests.spec.tsx @@ -14,10 +14,11 @@ import { fireEvent, render, screen, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { I18nextProvider } from 'react-i18next'; import { Provider } from 'react-redux'; -import { MemoryRouter, Route, Routes } from 'react-router-dom'; +import { BrowserRouter, MemoryRouter, Route, Routes } from 'react-router-dom'; import { store } from 'state/store'; import { StaticMockLink } from 'utils/StaticMockLink'; -import i18n from 'utils/i18nForTest'; +import i18nForTest from 'utils/i18nForTest'; +const i18n = i18nForTest; import Requests from './Requests'; import type { ApolloLink } from '@apollo/client'; import { @@ -58,6 +59,14 @@ const t = { ...JSON.parse(JSON.stringify(i18n.getDataByLanguage('en')?.errors ?? {})), }; +async function wait(ms = 100): Promise { + await act(() => { + return new Promise((resolve) => { + setTimeout(resolve, ms); + }); + }); +} + const renderRequests = (link: ApolloLink): RenderResult => { return render( @@ -235,3 +244,45 @@ describe('Testing Requests Screen', () => { }); }); }); + +describe('Requests Component CSS Styling', () => { + const renderComponent = (): RenderResult => { + return render( + + + + + + + + + , + ); + }; + + test('DataGrid should have correct styling', async () => { + const { container } = renderComponent(); + await wait(); + + const dataGrid = container.querySelector('.MuiDataGrid-root'); + expect(dataGrid).toBeInTheDocument(); + expect(dataGrid).toHaveClass('MuiDataGrid-root'); + expect(dataGrid).toHaveStyle({ + backgroundColor: 'white', + borderRadius: '16px', + }); + }); + + test('Sort button container should have correct spacing', async () => { + const { container } = renderComponent(); + await wait(); + + const sortContainer = container.querySelector('.d-flex.gap-3.mb-1'); + expect(sortContainer).toBeInTheDocument(); + + const sortButtonWrapper = container.querySelector( + '.d-flex.justify-space-between.align-items-center.gap-3', + ); + expect(sortButtonWrapper).toBeInTheDocument(); + }); +}); diff --git a/src/screens/EventVolunteers/Requests/Requests.tsx b/src/screens/EventVolunteers/Requests/Requests.tsx index d8efd92a90..9ec5b1fbd2 100644 --- a/src/screens/EventVolunteers/Requests/Requests.tsx +++ b/src/screens/EventVolunteers/Requests/Requests.tsx @@ -23,6 +23,17 @@ import { debounce } from '@mui/material'; import SortingButton from 'subComponents/SortingButton'; const dataGridStyle = { + backgroundColor: 'white', + borderRadius: '16px', + '& .MuiDataGrid-columnHeaders': { + border: 'none', + }, + '& .MuiDataGrid-cell': { + border: 'none', + }, + '& .MuiDataGrid-columnSeparator': { + display: 'none', + }, '&.MuiDataGrid-root .MuiDataGrid-cell:focus-within': { outline: 'none !important', }, @@ -155,7 +166,7 @@ function requests(): JSX.Element { align: 'center', headerAlign: 'center', sortable: false, - headerClassName: `${styles.tableHeaders}`, + headerClassName: `${styles.tableHeader}`, renderCell: (params: GridCellParams) => { return params.row.id; }, @@ -168,7 +179,7 @@ function requests(): JSX.Element { minWidth: 100, headerAlign: 'center', sortable: false, - headerClassName: `${styles.tableHeaders}`, + headerClassName: `${styles.tableHeader}`, renderCell: (params: GridCellParams) => { const { firstName, lastName, image } = params.row.volunteer.user; return ( @@ -206,7 +217,7 @@ function requests(): JSX.Element { minWidth: 150, align: 'center', headerAlign: 'center', - headerClassName: `${styles.tableHeaders}`, + headerClassName: `${styles.tableHeader}`, sortable: false, renderCell: (params: GridCellParams) => { return dayjs(params.row.createdAt).format('DD/MM/YYYY'); @@ -220,7 +231,7 @@ function requests(): JSX.Element { minWidth: 100, headerAlign: 'center', sortable: false, - headerClassName: `${styles.tableHeaders}`, + headerClassName: `${styles.tableHeader}`, renderCell: (params: GridCellParams) => { return ( <> @@ -252,8 +263,11 @@ function requests(): JSX.Element { return (
{/* Header with search, filter and Create Button */} -
-
+
+
@@ -351,6 +357,7 @@ function volunteerGroups(): JSX.Element { variant="success" onClick={() => handleModalClick(null, ModalState.SAME)} style={{ marginTop: '11px' }} + className={styles.actionsButton} data-testid="createGroupBtn" > diff --git a/src/screens/EventVolunteers/Volunteers/Volunteers.tsx b/src/screens/EventVolunteers/Volunteers/Volunteers.tsx index 1cd7a19e88..280be48f39 100644 --- a/src/screens/EventVolunteers/Volunteers/Volunteers.tsx +++ b/src/screens/EventVolunteers/Volunteers/Volunteers.tsx @@ -35,6 +35,17 @@ enum ModalState { } const dataGridStyle = { + backgroundColor: 'white', + borderRadius: '16px', + '& .MuiDataGrid-columnHeaders': { + border: 'none', + }, + '& .MuiDataGrid-cell': { + border: 'none', + }, + '& .MuiDataGrid-columnSeparator': { + display: 'none', + }, '&.MuiDataGrid-root .MuiDataGrid-cell:focus-within': { outline: 'none !important', }, @@ -174,7 +185,7 @@ function volunteers(): JSX.Element { minWidth: 100, headerAlign: 'center', sortable: false, - headerClassName: `${styles.tableHeaders}`, + headerClassName: `${styles.tableHeader}`, renderCell: (params: GridCellParams) => { const { _id, firstName, lastName, image } = params.row.user; return ( @@ -214,7 +225,7 @@ function volunteers(): JSX.Element { minWidth: 100, headerAlign: 'center', sortable: false, - headerClassName: `${styles.tableHeaders}`, + headerClassName: `${styles.tableHeader}`, renderCell: (params: GridCellParams) => { return ( { return (
{ return ( @@ -273,7 +284,7 @@ function volunteers(): JSX.Element { minWidth: 100, headerAlign: 'center', sortable: false, - headerClassName: `${styles.tableHeaders}`, + headerClassName: `${styles.tableHeader}`, renderCell: (params: GridCellParams) => { return ( <> @@ -305,8 +316,8 @@ function volunteers(): JSX.Element { return (
{/* Header with search, filter and Create Button */} -
-
+
+
{ setSearchValue(e.target.value); @@ -324,8 +335,7 @@ function volunteers(): JSX.Element { />