Skip to content

Commit 3964b4d

Browse files
committed
Fix: Resolved failed test cases
1 parent bbc126d commit 3964b4d

File tree

1 file changed

+131
-110
lines changed

1 file changed

+131
-110
lines changed

src/components/OrganizationCard/OrganizationCard.tsx

Lines changed: 131 additions & 110 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
/* eslint-disable react/destructuring-assignment */
21
import React from 'react';
32
import styles from './OrganizationCard.module.css';
43
import { Button } from 'react-bootstrap';
@@ -10,15 +9,17 @@ import {
109
JOIN_PUBLIC_ORGANIZATION,
1110
SEND_MEMBERSHIP_REQUEST,
1211
} from 'GraphQl/Mutations/OrganizationMutations';
13-
import { useMutation, useQuery, ApolloError } from '@apollo/client';
12+
import { useMutation, useQuery } from '@apollo/client';
1413
import {
1514
USER_JOINED_ORGANIZATIONS,
1615
USER_ORGANIZATION_CONNECTION,
1716
} from 'GraphQl/Queries/OrganizationQueries';
17+
import useLocalStorage from 'utils/useLocalstorage';
1818
import Avatar from 'components/Avatar/Avatar';
1919
import { useNavigate } from 'react-router-dom';
20+
import { ApolloError } from '@apollo/client';
2021

21-
import { useLocalStorage } from 'utils/useLocalstorage';
22+
const { getItem } = useLocalStorage();
2223

2324
interface InterfaceOrganizationCardProps {
2425
id: string;
@@ -48,88 +49,103 @@ interface InterfaceOrganizationCardProps {
4849
}[];
4950
}
5051

51-
function OrganizationCard({
52-
id,
53-
name,
54-
image,
55-
description,
56-
admins,
57-
members,
58-
address,
59-
membershipRequestStatus,
60-
userRegistrationRequired,
61-
membershipRequests,
62-
}: InterfaceOrganizationCardProps): JSX.Element {
63-
const { getItem } = useLocalStorage();
64-
const userId = getItem('userId');
65-
52+
/**
53+
* Displays an organization card with options to join or manage membership.
54+
*
55+
* Shows the organization's name, image, description, address, number of admins and members,
56+
* and provides buttons for joining, withdrawing membership requests, or visiting the organization page.
57+
*
58+
* @param props - The properties for the organization card.
59+
* @param id - The unique identifier of the organization.
60+
* @param name - The name of the organization.
61+
* @param image - The URL of the organization's image.
62+
* @param description - A description of the organization.
63+
* @param admins - The list of admins with their IDs.
64+
* @param members - The list of members with their IDs.
65+
* @param address - The address of the organization including city, country code, line1, postal code, and state.
66+
* @param membershipRequestStatus - The status of the membership request (accepted, pending, or empty).
67+
* @param userRegistrationRequired - Indicates if user registration is required to join the organization.
68+
* @param membershipRequests - The list of membership requests with user IDs.
69+
*
70+
* @returns The organization card component.
71+
*/
72+
const userId: string | null = getItem('userId');
73+
74+
function OrganizationCard(props: InterfaceOrganizationCardProps): JSX.Element {
6675
const { t } = useTranslation('translation', {
6776
keyPrefix: 'users',
6877
});
6978
const { t: tCommon } = useTranslation('common');
7079

7180
const navigate = useNavigate();
7281

82+
// Mutations for handling organization memberships
7383
const [sendMembershipRequest] = useMutation(SEND_MEMBERSHIP_REQUEST, {
7484
refetchQueries: [
75-
{ query: USER_ORGANIZATION_CONNECTION, variables: { id } },
85+
{ query: USER_ORGANIZATION_CONNECTION, variables: { id: props.id } },
7686
],
7787
});
78-
7988
const [joinPublicOrganization] = useMutation(JOIN_PUBLIC_ORGANIZATION, {
8089
refetchQueries: [
81-
{ query: USER_ORGANIZATION_CONNECTION, variables: { id } },
90+
{ query: USER_ORGANIZATION_CONNECTION, variables: { id: props.id } },
8291
],
8392
});
84-
8593
const [cancelMembershipRequest] = useMutation(CANCEL_MEMBERSHIP_REQUEST, {
8694
refetchQueries: [
87-
{ query: USER_ORGANIZATION_CONNECTION, variables: { id } },
95+
{ query: USER_ORGANIZATION_CONNECTION, variables: { id: props.id } },
8896
],
8997
});
90-
9198
const { refetch } = useQuery(USER_JOINED_ORGANIZATIONS, {
9299
variables: { id: userId },
93100
});
94101

102+
/**
103+
* Handles joining the organization. Sends a membership request if registration is required,
104+
* otherwise joins the public organization directly. Displays success or error messages.
105+
*/
95106
async function joinOrganization(): Promise<void> {
96107
try {
97-
if (userRegistrationRequired) {
108+
if (props.userRegistrationRequired) {
98109
await sendMembershipRequest({
99110
variables: {
100-
organizationId: id,
111+
organizationId: props.id,
101112
},
102113
});
103-
toast.success(t('MembershipRequestSent'));
114+
toast.success(t('MembershipRequestSent') as string);
104115
} else {
105116
await joinPublicOrganization({
106117
variables: {
107-
organizationId: id,
118+
organizationId: props.id,
108119
},
109120
});
110-
toast.success(t('orgJoined'));
121+
toast.success(t('orgJoined') as string);
111122
}
112123
refetch();
113124
} catch (error: unknown) {
114-
if (error instanceof ApolloError) {
115-
const errorCode = error.graphQLErrors[0]?.extensions?.code;
125+
/* istanbul ignore next */
126+
if (error instanceof Error) {
127+
const apolloError = error as ApolloError;
128+
const errorCode = apolloError.graphQLErrors[0]?.extensions?.code;
129+
116130
if (errorCode === 'ALREADY_MEMBER') {
117-
toast.error(t('AlreadyJoined'));
131+
toast.error(t('AlreadyJoined') as string);
118132
} else {
119-
toast.error(t('errorOccured'));
133+
toast.error(t('errorOccured') as string);
120134
}
121135
}
122136
}
123137
}
124138

139+
/**
140+
* Handles withdrawing a membership request. Finds the request for the current user and cancels it.
141+
*/
125142
async function withdrawMembershipRequest(): Promise<void> {
143+
const membershipRequest = props.membershipRequests.find(
144+
(request) => request.user._id === userId,
145+
);
126146
try {
127-
const membershipRequest = membershipRequests.find(
128-
(request) => request.user._id === userId,
129-
);
130-
131147
if (!membershipRequest) {
132-
toast.error(t('MembershipRequestNotFound'));
148+
toast.error(t('MembershipRequestNotFound') as string);
133149
return;
134150
}
135151

@@ -138,84 +154,89 @@ function OrganizationCard({
138154
membershipRequestId: membershipRequest._id,
139155
},
140156
});
141-
toast.success(t('MembershipRequestWithdrawn'));
142-
} catch (error: unknown) {
143-
console.error(error);
144-
toast.error(t('errorOccured'));
157+
158+
toast.success(t('MembershipRequestWithdrawn') as string);
159+
} catch (error) {
160+
toast.error(t('errorOccured') as string);
145161
}
146162
}
147163

148164
return (
149-
<div className={styles.orgCard}>
150-
<div className={styles.innerContainer}>
151-
<div className={styles.orgImgContainer}>
152-
{image ? (
153-
<img src={image} alt={`${name} image`} />
154-
) : (
155-
<Avatar
156-
name={name}
157-
alt={`${name} image`}
158-
dataTestId="emptyContainerForImage"
159-
/>
160-
)}
161-
</div>
162-
<div className={styles.content}>
163-
<Tooltip title={name} placement="top-end">
164-
<h4 className={`${styles.orgName} fw-semibold`}>{name}</h4>
165-
</Tooltip>
166-
<h6 className={`${styles.orgdesc} fw-semibold`}>
167-
<span>{description}</span>
168-
</h6>
169-
{address && address.city && (
170-
<div className={styles.address}>
171-
<h6 className="text-secondary">
172-
<span className="address-line">{address.line1}, </span>
173-
<span className="address-line">{address.city}, </span>
174-
<span className="address-line">{address.countryCode}</span>
175-
</h6>
176-
</div>
177-
)}
178-
<h6 className={styles.orgadmin}>
179-
{tCommon('admins')}: <span>{admins?.length}</span> &nbsp; &nbsp;
180-
&nbsp; {tCommon('members')}: <span>{members?.length}</span>
181-
</h6>
165+
<>
166+
<div className={styles.orgCard}>
167+
<div className={styles.innerContainer}>
168+
<div className={styles.orgImgContainer}>
169+
{props.image ? (
170+
<img src={props.image} alt={`${props.name} image`} />
171+
) : (
172+
<Avatar
173+
name={props.name}
174+
alt={`${props.name} image`}
175+
dataTestId="emptyContainerForImage"
176+
/>
177+
)}
178+
</div>
179+
<div className={styles.content}>
180+
<Tooltip title={props.name} placement="top-end">
181+
<h4 className={`${styles.orgName} fw-semibold`}>{props.name}</h4>
182+
</Tooltip>
183+
<h6 className={`${styles.orgdesc} fw-semibold`}>
184+
<span>{props.description}</span>
185+
</h6>
186+
{props.address && props.address.city && (
187+
<div className={styles.address}>
188+
<h6 className="text-secondary">
189+
<span className="address-line">{props.address.line1}, </span>
190+
<span className="address-line">{props.address.city}, </span>
191+
<span className="address-line">
192+
{props.address.countryCode}
193+
</span>
194+
</h6>
195+
</div>
196+
)}
197+
<h6 className={styles.orgadmin}>
198+
{tCommon('admins')}: <span>{props.admins?.length}</span> &nbsp;
199+
&nbsp; &nbsp; {tCommon('members')}:{' '}
200+
<span>{props.members?.length}</span>
201+
</h6>
202+
</div>
182203
</div>
204+
{props.membershipRequestStatus === 'accepted' && (
205+
<Button
206+
variant="success"
207+
data-testid="manageBtn"
208+
className={styles.joinedBtn}
209+
onClick={() => {
210+
navigate(`/user/organization/${props.id}`);
211+
}}
212+
>
213+
{t('visit')}
214+
</Button>
215+
)}
216+
217+
{props.membershipRequestStatus === 'pending' && (
218+
<Button
219+
variant="danger"
220+
onClick={withdrawMembershipRequest}
221+
data-testid="withdrawBtn"
222+
className={styles.withdrawBtn}
223+
>
224+
{t('withdraw')}
225+
</Button>
226+
)}
227+
228+
{props.membershipRequestStatus === '' && (
229+
<Button
230+
onClick={joinOrganization}
231+
data-testid="joinBtn"
232+
className={styles.joinBtn}
233+
variant="outline-success"
234+
>
235+
{t('joinNow')}
236+
</Button>
237+
)}
183238
</div>
184-
{membershipRequestStatus === 'accepted' && (
185-
<Button
186-
variant="success"
187-
data-testid="manageBtn"
188-
className={styles.joinedBtn}
189-
onClick={() => {
190-
navigate(`/user/organization/${id}`);
191-
}}
192-
>
193-
{t('visit')}
194-
</Button>
195-
)}
196-
197-
{membershipRequestStatus === 'pending' && (
198-
<Button
199-
variant="danger"
200-
onClick={withdrawMembershipRequest}
201-
data-testid="withdrawBtn"
202-
className={styles.withdrawBtn}
203-
>
204-
{t('withdraw')}
205-
</Button>
206-
)}
207-
208-
{membershipRequestStatus === '' && (
209-
<Button
210-
onClick={joinOrganization}
211-
data-testid="joinBtn"
212-
className={styles.joinBtn}
213-
variant="outline-success"
214-
>
215-
{t('joinNow')}
216-
</Button>
217-
)}
218-
</div>
239+
</>
219240
);
220241
}
221242

0 commit comments

Comments
 (0)