-
-
Notifications
You must be signed in to change notification settings - Fork 808
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
'Visit' Button Feature Added to Joined Organizations Filter #3232
base: develop-postgres
Are you sure you want to change the base?
'Visit' Button Feature Added to Joined Organizations Filter #3232
Conversation
…he Talawa User Portal
WalkthroughThis pull request introduces comprehensive changes to the Changes
Assessment against linked issues
Possibly related issues
Possibly related PRs
Suggested labels
Suggested reviewers
Poem
Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media? 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
Documentation and Community
|
Our Pull Request Approval ProcessThanks for contributing! Testing Your CodeRemember, your PRs won't be reviewed until these criteria are met:
Our policies make our code better. ReviewersDo not assign reviewers. Our Queue Monitors will review your PR and assign them.
Reviewing Your CodeYour reviewer(s) will have the following roles:
CONTRIBUTING.mdRead our CONTRIBUTING.md file. Most importantly:
Other
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 4
🧹 Nitpick comments (12)
src/components/OrganizationCard/OrganizationCard.tsx (6)
184-186
: Safely renderprops.description
to prevent potential errorsIf
props.description
isundefined
ornull
, rendering it directly could cause unintended output or errors. Consider conditionally rendering the description only if it exists.Modify the code to:
{props.description && ( <h6 className={`${styles.orgdesc} fw-semibold`}> <span>{props.description}</span> </h6> )}🧰 Tools
🪛 Biome (1.9.4)
[error] 186-186: Change to an optional chain.
Unsafe fix: Change to an optional chain.
(lint/complexity/useOptionalChain)
72-73
: EnsureuserId
is notnull
before using it in queriesSince
userId
can benull
, using it directly in GraphQL queries may result in errors or unintended behavior. Consider adding a null check before using it inuseQuery
or provide a default value.Example:
const userId = getItem('userId'); if (userId) { const { refetch } = useQuery(USER_JOINED_ORGANIZATIONS, { variables: { id: userId }, }); // Rest of your code that depends on userId }Alternatively, you can handle the null case gracefully within the component or redirect the user to log in if
userId
is not available.
107-136
: Handle potential errors more comprehensively injoinOrganization
The error handling in
joinOrganization
assumes that the error is anApolloError
withgraphQLErrors
. However, there's a possibility of other errors occurring. Consider adding a general error message or logging for unexpected error types.Modify the catch block to handle unexpected errors:
} catch (error: unknown) { if (error instanceof ApolloError) { const errorCode = error.graphQLErrors[0]?.extensions?.code; if (errorCode === 'ALREADY_MEMBER') { toast.error(t('AlreadyJoined') as string); } else { toast.error(t('errorOccured') as string); } } else { // Handle non-ApolloError types toast.error(t('unexpectedError') as string); console.error('An unexpected error occurred:', error); } }
143-145
: Improve type safety when findingmembershipRequest
When finding the
membershipRequest
, ensure thatuserId
is notnull
to avoid potential errors.Add a null check for
userId
:if (!userId) { toast.error(t('UserNotLoggedIn') as string); return; } const membershipRequest = props.membershipRequests.find( (request) => request.user._id === userId, );
198-200
: Handle undefinedprops.admins
andprops.members
safelyIn cases where
props.admins
orprops.members
might beundefined
, using.length
may cause errors. Consider providing default values to ensure safe access.Modify the code to provide default empty arrays:
{tCommon('admins')}: <span>{props.admins?.length ?? 0}</span> {tCommon('members')}: <span>{props.members?.length ?? 0}</span>
170-177
: Simplify image rendering logicYou can simplify the conditional rendering of the organization image by leveraging short-circuit evaluation.
Simplify the code as follows:
<div className={styles.orgImgContainer}> {props.image ? ( <img src={props.image} alt={`${props.name} image`} /> ) : ( <Avatar name={props.name} alt={`${props.name} image`} dataTestId="emptyContainerForImage" /> )} </div>This maintains readability and reduces unnecessary complexity.
src/components/OrganizationCard/OrganizationCard.spec.tsx (2)
168-209
: Separate tests for each membership status to improve clarityCurrently, the test
displays correct button based on membership status
usesrerender
to test different statuses within a single test case. Separating these into individual test cases enhances readability and maintainability.Refactor the tests as follows:
test('renders "Join Now" button when membershipRequestStatus is empty', () => { render( // ... <OrganizationCard {...defaultProps} membershipRequestStatus="" /> // ... ); expect(screen.getByTestId('joinBtn')).toBeInTheDocument(); }); test('renders "Visit" button when membershipRequestStatus is accepted', () => { render( // ... <OrganizationCard {...defaultProps} membershipRequestStatus="accepted" /> // ... ); const visitButton = screen.getByTestId('manageBtn'); expect(visitButton).toBeInTheDocument(); fireEvent.click(visitButton); expect(mockNavigate).toHaveBeenCalledWith('/user/organization/123'); }); test('renders "Withdraw" button when membershipRequestStatus is pending', () => { render( // ... <OrganizationCard {...defaultProps} membershipRequestStatus="pending" /> // ... ); expect(screen.getByTestId('withdrawBtn')).toBeInTheDocument(); });
19-23
: Avoid side effects in mocks by usingjest.fn()
within the mock scopeTo ensure that mocks do not leak between tests, consider defining
mockNavigate
within the mock scope rather than at the module level.Modify the mock setup:
jest.mock('react-router-dom', () => { const originalModule = jest.requireActual('react-router-dom'); return { ...originalModule, useNavigate: jest.fn(), }; });Then, within your tests, you can access
useNavigate
:import { useNavigate } from 'react-router-dom'; // Inside your test const mockNavigate = useNavigate() as jest.Mock; // Now you can assert on `mockNavigate`src/screens/UserPortal/Organizations/Organizations.tsx (4)
254-258
: EnsuremembershipRequestStatus
is accurately determinedIn the mapping function, consider handling cases where
membershipRequestStatus
might not be'accepted'
or may be undefined. This ensures thatisJoined
reflects the actual membership status.Add a default case for
membershipRequestStatus
:return { ...organization, membershipRequestStatus, isJoined: membershipRequestStatus === 'accepted', };Ensure that
membershipRequestStatus
is set correctly and consider handling other statuses like'pending'
if applicable.
Line range hint
98-100
: Check fornull
userId
before using it in queriesSince
userId
can benull
, using it directly inuseQuery
may cause issues. Add a null check or default handling to prevent potential errors.Example:
const userId: string | null = getItem('userId'); if (userId) { const { data: joinedOrganizationsData } = useQuery(USER_JOINED_ORGANIZATIONS, { variables: { id: userId }, }); const { data: createdOrganizationsData } = useQuery( USER_CREATED_ORGANIZATIONS, { variables: { id: userId }, }, ); } else { // Handle the case when userId is null, e.g., redirect to login }This ensures that queries relying on
userId
do not execute with invalid parameters.
266-272
: Handle undefined data when mappingjoinedOrganizations
When mapping over
joinedOrganizations
, ensure that the nested properties are notundefined
to prevent runtime errors.Modify the code:
const organizations = joinedOrganizationsData.users[0]?.user?.joinedOrganizations?.map( (org: InterfaceOrganization) => ({ ...org, membershipRequestStatus: 'accepted', isJoined: true, }), ) || [];Adding
?
before.map
ensures that the code does not attempt to map overundefined
.
281-287
: Handle undefined data when mappingcreatedOrganizations
Similar to the previous comment, ensure that
createdOrganizations
is defined before mapping.Modify the code:
const organizations = createdOrganizationsData.users[0]?.appUserProfile?.createdOrganizations?.map( (org: InterfaceOrganization) => ({ ...org, membershipRequestStatus: 'accepted', isJoined: true, }), ) || [];This prevents runtime errors if
createdOrganizations
isundefined
.
📜 Review details
Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (5)
eslint.config.cjs
(1 hunks)eslint.config.js
(1 hunks)src/components/OrganizationCard/OrganizationCard.spec.tsx
(2 hunks)src/components/OrganizationCard/OrganizationCard.tsx
(1 hunks)src/screens/UserPortal/Organizations/Organizations.tsx
(2 hunks)
🧰 Additional context used
🪛 GitHub Actions: PR Workflow
eslint.config.cjs
[error] SyntaxError: Unexpected identifier 'eslint' - Possible configuration file syntax error
🪛 Biome (1.9.4)
eslint.config.js
[error] 17-17: Expected a semicolon or an implicit semicolon after a statement, but found none
An explicit or implicit semicolon is expected here...
...Which is required to end this statement
(parse)
[error] 17-17: Expected a semicolon or an implicit semicolon after a statement, but found none
An explicit or implicit semicolon is expected here...
...Which is required to end this statement
(parse)
src/components/OrganizationCard/OrganizationCard.tsx
[error] 186-186: Change to an optional chain.
Unsafe fix: Change to an optional chain.
(lint/complexity/useOptionalChain)
⏰ Context from checks skipped due to timeout of 90000ms (1)
- GitHub Check: Analyse Code With CodeQL (javascript)
@gkbishnoi07 Please fix the failed tests and make sure coderabbit approves of the PR. |
@Cioppolo14 working on failed test cases |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
🧹 Nitpick comments (2)
src/components/OrganizationCard/OrganizationCard.tsx (2)
74-101
: Destructure props for better code readabilityMultiple static analysis tools suggest destructuring props. This would improve code readability and follow React best practices.
-function OrganizationCard(props: InterfaceOrganizationCardProps): JSX.Element { +function OrganizationCard({ + id, + name, + image, + description, + admins, + members, + address, + membershipRequestStatus, + userRegistrationRequired, + membershipRequests +}: InterfaceOrganizationCardProps): JSX.Element {🧰 Tools
🪛 GitHub Check: Performs linting, formatting, type-checking, checking for different source and target branch
[failure] 85-85:
Must use destructuring props assignment
[failure] 90-90:
Must use destructuring props assignment
[failure] 95-95:
Must use destructuring props assignment🪛 eslint
[error] 85-85: Must use destructuring props assignment
(react/destructuring-assignment)
[error] 90-90: Must use destructuring props assignment
(react/destructuring-assignment)
[error] 95-95: Must use destructuring props assignment
(react/destructuring-assignment)
186-196
: Use optional chaining for address checksSimplify the address check using optional chaining for better readability.
- {props.address && props.address.city && ( + {props.address?.city && (🧰 Tools
🪛 Biome (1.9.4)
[error] 186-186: Change to an optional chain.
Unsafe fix: Change to an optional chain.
(lint/complexity/useOptionalChain)
🪛 eslint
[error] 186-186: Must use destructuring props assignment
(react/destructuring-assignment)
[error] 186-186: Must use destructuring props assignment
(react/destructuring-assignment)
[error] 189-189: Must use destructuring props assignment
(react/destructuring-assignment)
[error] 190-190: Must use destructuring props assignment
(react/destructuring-assignment)
[error] 192-192: Must use destructuring props assignment
(react/destructuring-assignment)
📜 Review details
Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
src/components/OrganizationCard/OrganizationCard.tsx
(1 hunks)
🧰 Additional context used
🪛 GitHub Check: Performs linting, formatting, type-checking, checking for different source and target branch
src/components/OrganizationCard/OrganizationCard.tsx
[failure] 12-12:
'/home/runner/work/talawa-admin/talawa-admin/node_modules/@apollo/client/index.js' imported multiple times
[failure] 20-20:
All imports in the declaration are only used as types. Use import type
[failure] 20-20:
'/home/runner/work/talawa-admin/talawa-admin/node_modules/@apollo/client/index.js' imported multiple times
[failure] 85-85:
Must use destructuring props assignment
[failure] 90-90:
Must use destructuring props assignment
[failure] 95-95:
Must use destructuring props assignment
[failure] 108-108:
Must use destructuring props assignment
[failure] 111-111:
Must use destructuring props assignment
[failure] 118-118:
Must use destructuring props assignment
[failure] 143-143:
Must use destructuring props assignment
🪛 Biome (1.9.4)
src/components/OrganizationCard/OrganizationCard.tsx
[error] 186-186: Change to an optional chain.
Unsafe fix: Change to an optional chain.
(lint/complexity/useOptionalChain)
🪛 eslint
src/components/OrganizationCard/OrganizationCard.tsx
[error] 12-12: '@apollo/client' imported multiple times.
(import/no-duplicates)
[error] 20-20: All imports in the declaration are only used as types. Use import type
.
(@typescript-eslint/consistent-type-imports)
[error] 20-20: '@apollo/client' imported multiple times.
(import/no-duplicates)
[error] 85-85: Must use destructuring props assignment
(react/destructuring-assignment)
[error] 90-90: Must use destructuring props assignment
(react/destructuring-assignment)
[error] 95-95: Must use destructuring props assignment
(react/destructuring-assignment)
[error] 108-108: Must use destructuring props assignment
(react/destructuring-assignment)
[error] 111-111: Must use destructuring props assignment
(react/destructuring-assignment)
[error] 118-118: Must use destructuring props assignment
(react/destructuring-assignment)
[error] 143-143: Must use destructuring props assignment
(react/destructuring-assignment)
[error] 159-159: 'error' is defined but never used.
(@typescript-eslint/no-unused-vars)
[error] 169-169: Must use destructuring props assignment
(react/destructuring-assignment)
[error] 170-170: Must use destructuring props assignment
(react/destructuring-assignment)
[error] 170-170: Must use destructuring props assignment
(react/destructuring-assignment)
[error] 173-173: Must use destructuring props assignment
(react/destructuring-assignment)
[error] 174-174: Must use destructuring props assignment
(react/destructuring-assignment)
[error] 180-180: Must use destructuring props assignment
(react/destructuring-assignment)
[error] 181-181: Must use destructuring props assignment
(react/destructuring-assignment)
[error] 184-184: Must use destructuring props assignment
(react/destructuring-assignment)
[error] 186-186: Must use destructuring props assignment
(react/destructuring-assignment)
[error] 186-186: Must use destructuring props assignment
(react/destructuring-assignment)
[error] 189-189: Must use destructuring props assignment
(react/destructuring-assignment)
[error] 190-190: Must use destructuring props assignment
(react/destructuring-assignment)
[error] 192-192: Must use destructuring props assignment
(react/destructuring-assignment)
[error] 198-198: Must use destructuring props assignment
(react/destructuring-assignment)
[error] 200-200: Must use destructuring props assignment
(react/destructuring-assignment)
[error] 204-204: Must use destructuring props assignment
(react/destructuring-assignment)
[error] 210-210: Must use destructuring props assignment
(react/destructuring-assignment)
[error] 217-217: Must use destructuring props assignment
(react/destructuring-assignment)
[error] 228-228: Must use destructuring props assignment
(react/destructuring-assignment)
🪛 GitHub Actions: PR Workflow
src/components/OrganizationCard/OrganizationCard.tsx
[error] 12-12: '/home/runner/work/talawa-admin/talawa-admin/node_modules/@apollo/client/index.js' imported multiple times (import/no-duplicates)
🔇 Additional comments (4)
src/components/OrganizationCard/OrganizationCard.tsx (4)
26-49
: LGTM! Well-structured interface definition.The interface properties are well-defined and properly typed, providing a comprehensive structure for organization data.
52-71
: LGTM! Excellent documentation.The JSDoc documentation is comprehensive and clearly describes all component props and functionality.
204-214
: LGTM! Visit button implementation.The Visit button implementation aligns with the PR objectives, providing direct navigation to organizations from the filter.
🧰 Tools
🪛 eslint
[error] 204-204: Must use destructuring props assignment
(react/destructuring-assignment)
[error] 210-210: Must use destructuring props assignment
(react/destructuring-assignment)
1-241
: Add unit tests for the new Visit button featureWhile the implementation looks good, the PR mentions that no tests were added. Consider adding tests for:
- Visit button rendering conditions
- Navigation functionality
- Different membership states
Would you like me to help generate the test cases for the Visit button feature?
🧰 Tools
🪛 GitHub Check: Performs linting, formatting, type-checking, checking for different source and target branch
[failure] 12-12:
'/home/runner/work/talawa-admin/talawa-admin/node_modules/@apollo/client/index.js' imported multiple times
[failure] 20-20:
All imports in the declaration are only used as types. Useimport type
[failure] 20-20:
'/home/runner/work/talawa-admin/talawa-admin/node_modules/@apollo/client/index.js' imported multiple times
[failure] 85-85:
Must use destructuring props assignment
[failure] 90-90:
Must use destructuring props assignment
[failure] 95-95:
Must use destructuring props assignment
[failure] 108-108:
Must use destructuring props assignment
[failure] 111-111:
Must use destructuring props assignment
[failure] 118-118:
Must use destructuring props assignment
[failure] 143-143:
Must use destructuring props assignment🪛 Biome (1.9.4)
[error] 186-186: Change to an optional chain.
Unsafe fix: Change to an optional chain.
(lint/complexity/useOptionalChain)
🪛 eslint
[error] 12-12: '@apollo/client' imported multiple times.
(import/no-duplicates)
[error] 20-20: All imports in the declaration are only used as types. Use
import type
.(@typescript-eslint/consistent-type-imports)
[error] 20-20: '@apollo/client' imported multiple times.
(import/no-duplicates)
[error] 85-85: Must use destructuring props assignment
(react/destructuring-assignment)
[error] 90-90: Must use destructuring props assignment
(react/destructuring-assignment)
[error] 95-95: Must use destructuring props assignment
(react/destructuring-assignment)
[error] 108-108: Must use destructuring props assignment
(react/destructuring-assignment)
[error] 111-111: Must use destructuring props assignment
(react/destructuring-assignment)
[error] 118-118: Must use destructuring props assignment
(react/destructuring-assignment)
[error] 143-143: Must use destructuring props assignment
(react/destructuring-assignment)
[error] 159-159: 'error' is defined but never used.
(@typescript-eslint/no-unused-vars)
[error] 169-169: Must use destructuring props assignment
(react/destructuring-assignment)
[error] 170-170: Must use destructuring props assignment
(react/destructuring-assignment)
[error] 170-170: Must use destructuring props assignment
(react/destructuring-assignment)
[error] 173-173: Must use destructuring props assignment
(react/destructuring-assignment)
[error] 174-174: Must use destructuring props assignment
(react/destructuring-assignment)
[error] 180-180: Must use destructuring props assignment
(react/destructuring-assignment)
[error] 181-181: Must use destructuring props assignment
(react/destructuring-assignment)
[error] 184-184: Must use destructuring props assignment
(react/destructuring-assignment)
[error] 186-186: Must use destructuring props assignment
(react/destructuring-assignment)
[error] 186-186: Must use destructuring props assignment
(react/destructuring-assignment)
[error] 189-189: Must use destructuring props assignment
(react/destructuring-assignment)
[error] 190-190: Must use destructuring props assignment
(react/destructuring-assignment)
[error] 192-192: Must use destructuring props assignment
(react/destructuring-assignment)
[error] 198-198: Must use destructuring props assignment
(react/destructuring-assignment)
[error] 200-200: Must use destructuring props assignment
(react/destructuring-assignment)
[error] 204-204: Must use destructuring props assignment
(react/destructuring-assignment)
[error] 210-210: Must use destructuring props assignment
(react/destructuring-assignment)
[error] 217-217: Must use destructuring props assignment
(react/destructuring-assignment)
[error] 228-228: Must use destructuring props assignment
(react/destructuring-assignment)
🪛 GitHub Actions: PR Workflow
[error] 12-12: '/home/runner/work/talawa-admin/talawa-admin/node_modules/@apollo/client/index.js' imported multiple times (import/no-duplicates)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (3)
src/components/OrganizationCard/OrganizationCard.tsx (3)
12-12
: Fix formatting in importsRemove the trailing comma after
useQuery
.-import { useMutation, useQuery, } from '@apollo/client'; +import { useMutation, useQuery } from '@apollo/client';🧰 Tools
🪛 eslint
[error] 12-12: Delete
,
(prettier/prettier)
🪛 GitHub Actions: PR Workflow
[warning] Code formatting issues detected. File needs to be formatted using Prettier.
113-143
: Improve error type handling in joinOrganizationThe error handling could be more type-safe. Consider creating a custom type for the GraphQL error structure.
+interface GraphQLErrorExtensions { + code: string; +} + +interface CustomGraphQLError extends ApolloError { + graphQLErrors: Array<{ + extensions?: GraphQLErrorExtensions; + }>; +} async function joinOrganization(): Promise<void> { try { // ... existing code ... } catch (error: unknown) { if (error instanceof Error) { - const apolloError = error as ApolloError; + const apolloError = error as CustomGraphQLError; const errorCode = apolloError.graphQLErrors[0]?.extensions?.code;🧰 Tools
🪛 GitHub Actions: PR Workflow
[warning] Code formatting issues detected. File needs to be formatted using Prettier.
189-197
: Optimize conditional rendering with optional chainingThe address check can be simplified using optional chaining.
-{address && address.city && ( +{address?.city && (🧰 Tools
🪛 Biome (1.9.4)
[error] 189-189: Change to an optional chain.
Unsafe fix: Change to an optional chain.
(lint/complexity/useOptionalChain)
🪛 GitHub Actions: PR Workflow
[warning] Code formatting issues detected. File needs to be formatted using Prettier.
📜 Review details
Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
src/components/OrganizationCard/OrganizationCard.tsx
(1 hunks)
🧰 Additional context used
🪛 Biome (1.9.4)
src/components/OrganizationCard/OrganizationCard.tsx
[error] 189-189: Change to an optional chain.
Unsafe fix: Change to an optional chain.
(lint/complexity/useOptionalChain)
🪛 eslint
src/components/OrganizationCard/OrganizationCard.tsx
[error] 12-12: Delete ,
(prettier/prettier)
🪛 GitHub Actions: PR Workflow
src/components/OrganizationCard/OrganizationCard.tsx
[warning] Code formatting issues detected. File needs to be formatted using Prettier.
⏰ Context from checks skipped due to timeout of 90000ms (1)
- GitHub Check: Analyse Code With CodeQL (javascript)
🔇 Additional comments (4)
src/components/OrganizationCard/OrganizationCard.tsx (4)
27-49
: LGTM! Well-structured interface definitionThe interface is well-defined with proper typing for all properties. The nested structures for
admins
,members
,address
, andmembershipRequests
provide good type safety.🧰 Tools
🪛 GitHub Actions: PR Workflow
[warning] Code formatting issues detected. File needs to be formatted using Prettier.
53-70
: LGTM! Excellent documentationThe JSDoc comments are comprehensive and well-structured, clearly documenting all parameters and their purposes.
🧰 Tools
🪛 GitHub Actions: PR Workflow
[warning] Code formatting issues detected. File needs to be formatted using Prettier.
86-111
: LGTM! Well-structured component setupGood practices observed:
- Proper translation setup with namespaces
- GraphQL mutations with appropriate refetch queries
- Clean organization of hooks and mutations
🧰 Tools
🪛 GitHub Actions: PR Workflow
[warning] Code formatting issues detected. File needs to be formatted using Prettier.
204-237
: LGTM! Clean conditional renderingThe button rendering logic is well-organized with clear conditions and appropriate variants for different states.
🧰 Tools
🪛 GitHub Actions: PR Workflow
[warning] Code formatting issues detected. File needs to be formatted using Prettier.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (4)
src/components/OrganizationCard/OrganizationCard.tsx (4)
53-70
: Consider adding usage examples to the documentation.The documentation is comprehensive but could be even more helpful with examples showing different membership states and how they affect the component's rendering.
94-108
: Consider extracting duplicate refetchQueries configuration.The refetchQueries configuration is repeated across multiple mutations. Consider extracting it to a constant to improve maintainability.
+const MEMBERSHIP_REFETCH_QUERIES = [ + { query: USER_ORGANIZATION_CONNECTION, variables: { id } }, +]; const [sendMembershipRequest] = useMutation(SEND_MEMBERSHIP_REQUEST, { - refetchQueries: [ - { query: USER_ORGANIZATION_CONNECTION, variables: { id } }, - ], + refetchQueries: MEMBERSHIP_REFETCH_QUERIES, }); const [joinPublicOrganization] = useMutation(JOIN_PUBLIC_ORGANIZATION, { - refetchQueries: [ - { query: USER_ORGANIZATION_CONNECTION, variables: { id } }, - ], + refetchQueries: MEMBERSHIP_REFETCH_QUERIES, }); const [cancelMembershipRequest] = useMutation(CANCEL_MEMBERSHIP_REQUEST, { - refetchQueries: [ - { query: USER_ORGANIZATION_CONNECTION, variables: { id } }, - ], + refetchQueries: MEMBERSHIP_REFETCH_QUERIES, });
131-142
: Consider creating a custom error type for better error handling.The error handling could be more specific by creating a custom type for GraphQL errors. This would make the error handling more type-safe and maintainable.
type OrganizationError = { code: 'ALREADY_MEMBER' | 'MEMBERSHIP_NOT_FOUND' | 'UNKNOWN_ERROR'; message: string; }; // Usage in error handling if (error instanceof ApolloError) { const errorCode = error.graphQLErrors[0]?.extensions?.code as OrganizationError['code']; // ... }
189-197
: Use optional chaining for safer address access.The address check can be simplified using optional chaining for better readability and safety.
-{address && address.city && ( +{address?.city && ( <div className={styles.address}> <h6 className="text-secondary"> - <span className="address-line">{address.line1}, </span> - <span className="address-line">{address.city}, </span> - <span className="address-line">{address.countryCode}</span> + <span className="address-line">{address?.line1}, </span> + <span className="address-line">{address?.city}, </span> + <span className="address-line">{address?.countryCode}</span> </h6> </div> )}🧰 Tools
🪛 Biome (1.9.4)
[error] 189-189: Change to an optional chain.
Unsafe fix: Change to an optional chain.
(lint/complexity/useOptionalChain)
📜 Review details
Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
src/components/OrganizationCard/OrganizationCard.tsx
(1 hunks)
🧰 Additional context used
🪛 Biome (1.9.4)
src/components/OrganizationCard/OrganizationCard.tsx
[error] 189-189: Change to an optional chain.
Unsafe fix: Change to an optional chain.
(lint/complexity/useOptionalChain)
⏰ Context from checks skipped due to timeout of 90000ms (1)
- GitHub Check: Test Application
🔇 Additional comments (3)
src/components/OrganizationCard/OrganizationCard.tsx (3)
12-12
: Consolidate duplicate imports from '@apollo/client'Combine the multiple imports from '@apollo/client' into a single import statement and use
import type
for type-only imports.-import { useMutation, useQuery } from '@apollo/client'; -import type { ApolloError } from '@apollo/client'; +import { useMutation, useQuery } from '@apollo/client'; +import type { ApolloError } from '@apollo/client';Also applies to: 20-20
28-49
: LGTM! Well-structured interface with comprehensive type definitions.The interface has been enhanced with well-defined types for organization properties including description, admins, members, address, and membership-related fields.
204-237
: LGTM! Well-implemented conditional rendering for membership states.The button rendering logic is clean and properly handles all membership states (accepted, pending, and new joins) with appropriate styling and functionality.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (3)
src/components/OrganizationCard/OrganizationCard.spec.tsx (3)
29-45
: Consider adding validation for required propsThe defaultProps object is well-structured, but consider adding JSDoc comments to document which props are required vs optional, especially for the new membershipRequestStatus prop.
Add documentation like this:
+/** + * Default props for OrganizationCard tests + * @property {string} id - Required. Organization ID + * @property {string} membershipRequestStatus - Required. Current membership status + */ const defaultProps = {
105-124
: Add error handling test cases for navigationWhile the basic navigation test is good, consider adding test cases for:
- Error handling when navigation fails
- Loading state during navigation
Add these test cases:
test('handles navigation errors gracefully', () => { mockNavigate.mockImplementationOnce(() => { throw new Error('Navigation failed'); }); // Test implementation }); test('shows loading state during navigation', () => { // Test implementation with loading state check });
47-171
: Consider grouping related test casesThe test cases are well-written but could be better organized using describe blocks to group related tests.
Consider restructuring like this:
describe('OrganizationCard', () => { describe('Rendering', () => { // Tests for basic rendering (with/without image) }); describe('Membership Status', () => { // Tests for different membership statuses }); describe('Navigation', () => { // Tests for navigation functionality }); });
📜 Review details
Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
package-lock.json
is excluded by!**/package-lock.json
📒 Files selected for processing (2)
package.json
(2 hunks)src/components/OrganizationCard/OrganizationCard.spec.tsx
(2 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (2)
- GitHub Check: Test Application
- GitHub Check: Analyse Code With CodeQL (javascript)
🔇 Additional comments (3)
package.json (1)
152-152
: Verify Jest upgrade compatibilityThe significant version jump in Jest (27.4.5 to 29.7.0) might introduce breaking changes. Ensure all existing tests are compatible with the new version.
Run this script to check for potential compatibility issues:
✅ Verification successful
Jest upgrade appears safe to proceed
The codebase uses modern Jest patterns and APIs that are compatible with Jest 29.x. The configuration and test implementations follow current best practices without any deprecated features.
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash # Description: Check for Jest breaking changes and compatibility issues # Search for Jest configuration files echo "Searching for Jest config files..." fd -e json -e js -e ts --full-path "jest.config" # Look for potentially affected test patterns echo "Checking for potentially affected test patterns..." rg -l "jest.mock|jest.spyOn|jest.fn" -g "*.spec.{ts,tsx,js,jsx}"Length of output: 378
Script:
#!/bin/bash # Check Jest configuration and test implementation echo "=== Jest Configuration ===" cat jest.config.js echo -e "\n=== Test Implementation ===" cat src/components/OrganizationCard/OrganizationCard.spec.tsxLength of output: 9088
src/components/OrganizationCard/OrganizationCard.spec.tsx (2)
20-27
: LGTM! Well-structured navigation mockThe navigation mock is properly implemented using jest.mock, which is essential for testing the Visit button's navigation functionality.
105-124
: LGTM! Tests align perfectly with PR objectivesThe test coverage for the Visit button feature is comprehensive, including:
- Correct button rendering based on membership status
- Navigation functionality
- Different membership states
Also applies to: 172-214
Exclude the sensitive files from your PR. Don't delete them. Your PR has too many unnecessary files that don’t relate to your issue. You can exclude them from the PR by running the commands below from the root directory of the repository
Please apply these changes to this file(s). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🧹 Nitpick comments (2)
src/screens/OrganizationTags/OrganizationTags.spec.tsx (1)
293-296
: Replace non-null assertions with proper error handling.The non-null assertions (
!
) on the form element should be replaced with proper error handling to improve type safety.- const form = screen.getByTestId('createTagSubmitBtn').closest('form'); - await act(async () => { - fireEvent.submit(form!); - }); + const submitBtn = screen.getByTestId('createTagSubmitBtn'); + const form = submitBtn.closest('form'); + if (!form) { + throw new Error('Form not found'); + } + await act(async () => { + fireEvent.submit(form); + });Also applies to: 312-314
🧰 Tools
🪛 eslint
[error] 295-295: Forbidden non-null assertion.
(@typescript-eslint/no-non-null-assertion)
src/components/OrganizationCard/OrganizationCard.spec.tsx (1)
179-214
: Consider splitting the membership status testsWhile the test is comprehensive, consider splitting it into separate test cases for better maintainability and clearer failure messages.
Here's a suggested approach:
describe('membership status buttons', () => { const renderComponent = (status: string) => { return render( <MockedProvider> <I18nextProvider i18n={i18nForTest}> <OrganizationCard {...defaultProps} membershipRequestStatus={status} /> </I18nextProvider> </MockedProvider> ); }; test('shows Join Now button for empty status', () => { renderComponent(""); expect(screen.getByTestId('joinBtn')).toBeInTheDocument(); }); test('shows Visit button for accepted status', () => { renderComponent("accepted"); expect(screen.getByTestId('manageBtn')).toBeInTheDocument(); }); test('shows Withdraw button for pending status', () => { renderComponent("pending"); expect(screen.getByTestId('withdrawBtn')).toBeInTheDocument(); }); });
📜 Review details
Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
src/components/OrganizationCard/OrganizationCard.spec.tsx
(2 hunks)src/screens/OrganizationTags/OrganizationTags.spec.tsx
(2 hunks)
🧰 Additional context used
📓 Learnings (1)
src/screens/OrganizationTags/OrganizationTags.spec.tsx (1)
Learnt from: meetulr
PR: PalisadoesFoundation/talawa-admin#2398
File: src/screens/OrganizationTags/OrganizationTags.test.tsx:184-0
Timestamp: 2024-11-12T10:40:58.655Z
Learning: In the `talawa-admin` project, it's acceptable for test cases in `src/screens/OrganizationTags/OrganizationTags.test.tsx` to test multiple behaviors within a single test function without needing to split them into smaller, focused tests.
🪛 Biome (1.9.4)
src/components/OrganizationCard/OrganizationCard.spec.tsx
[error] 27-28: Expected a property, a shorthand property, a getter, a setter, or a method but instead found '==='.
Expected a property, a shorthand property, a getter, a setter, or a method here.
(parse)
[error] 28-28: Expected an expression but instead found '==='.
Expected an expression here.
(parse)
[error] 28-28: Expected an expression but instead found '='.
Expected an expression here.
(parse)
[error] 25-28: Invalid assignment to { ...actual, BrowserRouter: ({ children }: { children: React.ReactNode }) => children, ======
This expression cannot be assigned to
(parse)
[error] 28-29: Expected an expression, or an assignment but instead found 'const'.
Expected an expression, or an assignment here.
(parse)
[error] 33-34: Expected a property, a shorthand property, a getter, a setter, or a method but instead found '>'.
Expected a property, a shorthand property, a getter, a setter, or a method here.
(parse)
[error] 34-34: Expected an expression but instead found '>>>'.
Expected an expression here.
(parse)
[error] 34-34: Expected an expression but instead found '>'.
Expected an expression here.
(parse)
[error] 34-34: numbers cannot be followed by identifiers directly after
an identifier cannot appear here
(parse)
[error] 36-36: Expected an expression but instead found '}'.
Expected an expression here.
(parse)
[error] 36-36: expected ,
but instead found ;
Remove ;
(parse)
[error] 25-28: The assignment should not be in an expression.
The use of assignments in expressions is confusing.
Expressions are often considered as side-effect free.
(lint/suspicious/noAssignInExpressions)
[error] 35-35: Unexpected label.
Only loops should be labeled.
The use of labels for other statements is suspicious and unfamiliar.
(lint/suspicious/noConfusingLabels)
[error] 35-35: This code is unreachable
... because this statement will return from the function beforehand
(lint/correctness/noUnreachable)
[error] 28-36: This code is unreachable
... because this statement will return from the function beforehand
(lint/correctness/noUnreachable)
🪛 GitHub Actions: PR Workflow
src/components/OrganizationCard/OrganizationCard.spec.tsx
[error] 20-23: Merge conflict marker encountered. The file contains unresolved Git merge conflict markers (<<<<<<< HEAD)
🪛 eslint
src/screens/OrganizationTags/OrganizationTags.spec.tsx
[error] 295-295: Forbidden non-null assertion.
(@typescript-eslint/no-non-null-assertion)
[error] 313-313: Forbidden non-null assertion.
(@typescript-eslint/no-non-null-assertion)
⏰ Context from checks skipped due to timeout of 90000ms (1)
- GitHub Check: Analyse Code With CodeQL (javascript)
🔇 Additional comments (4)
src/screens/OrganizationTags/OrganizationTags.spec.tsx (2)
Line range hint
277-320
: Well-structured test with clear steps and proper async handling!The test case is well organized with:
- Clear step-by-step comments
- Proper use of
act()
for state updates- Appropriate
waitFor
assertions for async operations🧰 Tools
🪛 eslint
[error] 295-295: Forbidden non-null assertion.
(@typescript-eslint/no-non-null-assertion)
[error] 313-313: Forbidden non-null assertion.
(@typescript-eslint/no-non-null-assertion)
51-52
: Verify if unused toast mocks are needed.The newly added
warn
andinfo
toast mocks aren't used in any test cases. Consider removing them if they're not required for upcoming changes.Run this script to check for usage of these toast types:
src/components/OrganizationCard/OrganizationCard.spec.tsx (2)
39-55
: Well-structured test data setupThe defaultProps object is comprehensive and includes all necessary fields for testing the OrganizationCard component, including the new fields required for the Visit button feature.
120-137
: Well-implemented Visit button testThe test case properly verifies both the presence of the Visit button and its navigation functionality when clicked.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (1)
src/components/OrganizationCard/OrganizationCard.spec.tsx (1)
48-205
: Consider adding error case testsWhile the happy path scenarios are well covered, consider adding tests for error cases such as:
- Invalid membership status
- Network errors when navigating
- Missing required props
Example test case:
test('handles invalid membership status gracefully', () => { render( <MockedProvider> <I18nextProvider i18n={i18nForTest}> <OrganizationCard {...defaultProps} membershipRequestStatus="invalid_status" /> </I18nextProvider> </MockedProvider>, ); // Verify fallback behavior expect(screen.getByTestId('joinBtn')).toBeInTheDocument(); });
📜 Review details
Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
src/components/OrganizationCard/OrganizationCard.spec.tsx
(2 hunks)src/screens/UserPortal/Organizations/Organizations.tsx
(3 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- src/screens/UserPortal/Organizations/Organizations.tsx
🔇 Additional comments (3)
src/components/OrganizationCard/OrganizationCard.spec.tsx (3)
Line range hint
1-28
: LGTM! Clean migration from Jest to VitestThe test setup and configuration are well-structured with proper imports and mocking.
30-46
: LGTM! Well-structured test dataThe defaultProps object provides comprehensive test data covering all component properties, including those needed for the new Visit button feature.
111-128
: LGTM! Visit button functionality is well testedThe test properly verifies both the rendering and navigation functionality of the Visit button.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
🧹 Nitpick comments (1)
src/screens/UserPortal/Organizations/Organizations.tsx (1)
Line range hint
167-235
: Extract duplicate membership status logic into a utility function.The membership status checking logic is duplicated across different useEffect hooks. This could lead to maintenance issues if the logic needs to be updated.
Consider extracting the logic into a utility function:
const determineOrganizationStatus = (organization: InterfaceOrganization, userId: string) => { let membershipRequestStatus = ''; if (organization.members.find((member: { _id: string }) => member._id === userId)) { membershipRequestStatus = 'accepted'; } else if ( organization.membershipRequests.find( (request: { user: { _id: string } }) => request.user._id === userId, ) ) { membershipRequestStatus = 'pending'; } return { membershipRequestStatus, isJoined: membershipRequestStatus === 'accepted', }; };
📜 Review details
Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
src/screens/UserPortal/Organizations/Organizations.tsx
(8 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (1)
- GitHub Check: Analyse Code With CodeQL (javascript)
🔇 Additional comments (2)
src/screens/UserPortal/Organizations/Organizations.tsx (2)
69-81
: LGTM! Component naming and state management improvements.The changes follow React best practices with proper component naming and improved type safety through explicit typing of the organizations state.
Line range hint
69-375
: Add test coverage for the Organizations component.The PR objectives mention failed tests, and there's no test coverage visible for this component. Consider adding tests for:
- Organization filtering functionality
- Pagination behavior
- Responsive drawer behavior
- Different organization modes (all, joined, created)
Let me check for existing test files:
Would you like me to help create the test suite for this component?
@palisadoes, I’ve added this function and it’s working well. I passed all the test cases in my local setup. However, I’m currently facing an issue with the GitHub test, where the formatting lint test is failing. I will find the issue and quickly resolve that. I also ran npx prettier --check . locally and got the message "All matched files use Prettier code style!" but the test still failed on GitHub. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🔭 Outside diff range comments (1)
src/screens/UserPortal/Organizations/Organizations.tsx (1)
Line range hint
167-188
: Refactor duplicate membership status logic.The membership status checking logic is duplicated between the two useEffect hooks. Consider extracting this logic into a utility function.
+const determineMembershipStatus = (organization: InterfaceOrganization, userId: string) => { + let membershipRequestStatus = ''; + if (organization.members.find((member: { _id: string }) => member._id === userId)) { + membershipRequestStatus = 'accepted'; + } else if ( + organization.membershipRequests.find( + (request: { user: { _id: string } }) => request.user._id === userId + ) + ) { + membershipRequestStatus = 'pending'; + } + return { + membershipRequestStatus, + isJoined: membershipRequestStatus === 'accepted' + }; +};Then use it in both useEffect hooks:
-let membershipRequestStatus = ''; -if (organization.members.find((member: { _id: string }) => member._id === userId)) - membershipRequestStatus = 'accepted'; -else if (organization.membershipRequests.find((request: { user: { _id: string } }) => request.user._id === userId)) - membershipRequestStatus = 'pending'; +const { membershipRequestStatus, isJoined } = determineMembershipStatus(organization, userId);Also applies to: 191-235
🧰 Tools
🪛 GitHub Actions: PR Workflow
[error] Missing TSDoc comment documentation
♻️ Duplicate comments (1)
src/screens/UserPortal/Organizations/Organizations.tsx (1)
244-244
: 🛠️ Refactor suggestionFix potential state update race conditions in click handlers.
The click handlers directly use the previous state value in the toggle operation, which could lead to incorrect state updates if multiple clicks occur rapidly.
-onClick={(): void => setHideDrawer(!hideDrawer)} +onClick={(): void => setHideDrawer((prev) => !prev)}Also applies to: 252-252
🧰 Tools
🪛 GitHub Actions: PR Workflow
[error] Missing TSDoc comment documentation
🧹 Nitpick comments (1)
src/screens/UserPortal/Organizations/Organizations.tsx (1)
325-355
: Simplify conditional rendering logic.The nested conditional rendering could be simplified for better readability.
- {loadingOrganizations ? ( - <div className="d-flex flex-row justify-content-center"> - <HourglassBottomIcon /> <span>Loading...</span> - </div> - ) : organizations && organizations.length > 0 ? ( - (rowsPerPage > 0 - ? organizations.slice( - page * rowsPerPage, - page * rowsPerPage + rowsPerPage, - ) - : organizations - ).map((organization: InterfaceOrganization) => { + {loadingOrganizations && ( + <div className="d-flex flex-row justify-content-center"> + <HourglassBottomIcon /> <span>Loading...</span> + </div> + )} + {!loadingOrganizations && organizations.length === 0 && ( + <span>{t('nothingToShow')}</span> + )} + {!loadingOrganizations && organizations.length > 0 && ( + <> + {(rowsPerPage > 0 + ? organizations.slice( + page * rowsPerPage, + page * rowsPerPage + rowsPerPage, + ) + : organizations + ).map((organization: InterfaceOrganization) => {🧰 Tools
🪛 GitHub Actions: PR Workflow
[error] Missing TSDoc comment documentation
📜 Review details
Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
src/screens/OrganizationTags/OrganizationTags.spec.tsx
(2 hunks)src/screens/UserPortal/Organizations/Organizations.tsx
(8 hunks)talawa-admin
(1 hunks)
✅ Files skipped from review due to trivial changes (1)
- talawa-admin
🚧 Files skipped from review as they are similar to previous changes (1)
- src/screens/OrganizationTags/OrganizationTags.spec.tsx
🧰 Additional context used
🪛 GitHub Actions: PR Workflow
src/screens/UserPortal/Organizations/Organizations.tsx
[error] Missing TSDoc comment documentation
⏰ Context from checks skipped due to timeout of 90000ms (1)
- GitHub Check: Analyse Code With CodeQL (javascript)
🔇 Additional comments (1)
src/screens/UserPortal/Organizations/Organizations.tsx (1)
113-125
: LGTM! Well-implemented resize handler.The resize handler implementation follows React best practices:
- Uses functional state updates to prevent race conditions
- Properly cleans up event listeners in the useEffect cleanup function
🧰 Tools
🪛 GitHub Actions: PR Workflow
[error] Missing TSDoc comment documentation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🔭 Outside diff range comments (1)
src/screens/UserPortal/Organizations/Organizations.tsx (1)
Line range hint
205-224
: Extract duplicate organization mapping logic.The organization mapping logic is duplicated in two useEffect hooks. Consider extracting it into a utility function:
+const mapOrganizationWithMembershipStatus = ( + organization: InterfaceOrganization, + userId: string, + includeIsJoined = false +) => { + let membershipRequestStatus = ''; + if ( + organization.members.find( + (member: { _id: string }) => member._id === userId, + ) + ) + membershipRequestStatus = 'accepted'; + else if ( + organization.membershipRequests.find( + (request: { user: { _id: string } }) => + request.user._id === userId, + ) + ) + membershipRequestStatus = 'pending'; + + return { + ...organization, + membershipRequestStatus, + ...(includeIsJoined && { isJoined: membershipRequestStatus === 'accepted' }), + }; +}; useEffect(() => { if (data) { - const orgs = data.organizationsConnection.map( - // ... current mapping logic - ); + const orgs = data.organizationsConnection.map((org) => + mapOrganizationWithMembershipStatus(org, userId) + ); setOrganizations(orgs); } }, [data, userId]); useEffect(() => { if (mode === 0 && data) { - const orgs = data.organizationsConnection.map( - // ... current mapping logic - ); + const orgs = data.organizationsConnection.map((org) => + mapOrganizationWithMembershipStatus(org, userId, true) + ); setOrganizations(orgs); } // ... rest of the effect }, [mode, data, joinedOrganizationsData, createdOrganizationsData, userId]);Also applies to: 229-254
🧰 Tools
🪛 eslint
[error] 196-196: 'handleSearchByBtnClick' is assigned a value but never used.
(@typescript-eslint/no-unused-vars)
🧹 Nitpick comments (2)
src/components/OrganizationCard/OrganizationCard.spec.tsx (1)
54-80
: Enhance image rendering test coverage.Consider adding assertions to verify the image source attribute:
expect(screen.getByRole('img')).toBeInTheDocument(); + const imgElement = screen.getByRole('img'); + expect(imgElement).toHaveAttribute('src', defaultProps.image);🧰 Tools
🪛 GitHub Actions: PR Workflow
[warning] Code style issues found. File needs to be formatted using Prettier.
src/screens/UserPortal/Organizations/Organizations.tsx (1)
Line range hint
21-47
: Consider consolidating duplicate interface properties.The
InterfaceOrganizationCardProps
andInterfaceOrganization
interfaces share identical properties. Consider creating a base interface to avoid duplication.+interface BaseOrganization { + id: string; + name: string; + image: string; + description: string; + admins: []; + members: []; + address: { + city: string; + countryCode: string; + line1: string; + postalCode: string; + state: string; + }; + membershipRequestStatus: string; + userRegistrationRequired: boolean; + membershipRequests: { + _id: string; + user: { + _id: string; + }; + }[]; +} -interface InterfaceOrganizationCardProps { - // ... current properties -} +interface InterfaceOrganizationCardProps extends BaseOrganization {} -interface InterfaceOrganization { - // ... current properties -} +interface InterfaceOrganization extends BaseOrganization {}🧰 Tools
🪛 eslint
[error] 24-24: 'InterfaceOrganizationCardProps' is defined but never used.
(@typescript-eslint/no-unused-vars)
📜 Review details
Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
src/components/OrganizationCard/OrganizationCard.spec.tsx
(1 hunks)src/screens/UserPortal/Organizations/Organizations.tsx
(7 hunks)
🧰 Additional context used
🪛 eslint
src/screens/UserPortal/Organizations/Organizations.tsx
[error] 78-78: tsdoc-malformed-inline-tag: Expecting a TSDoc tag starting with "{@"
(tsdoc/syntax)
[error] 78-78: tsdoc-escape-right-brace: The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag
(tsdoc/syntax)
[error] 85-85: 'hideDrawer' is assigned a value but never used.
(@typescript-eslint/no-unused-vars)
[error] 86-86: 'page' is assigned a value but never used.
(@typescript-eslint/no-unused-vars)
[error] 87-87: 'rowsPerPage' is assigned a value but never used.
(@typescript-eslint/no-unused-vars)
[error] 88-88: 'organizations' is assigned a value but never used.
(@typescript-eslint/no-unused-vars)
[error] 92-92: 'setMode' is assigned a value but never used.
(@typescript-eslint/no-unused-vars)
[error] 144-144: tsdoc-param-tag-with-invalid-type: The @param block should not include a JSDoc-style '{type}'
(tsdoc/syntax)
[error] 145-145: tsdoc-param-tag-with-invalid-type: The @param block should not include a JSDoc-style '{type}'
(tsdoc/syntax)
[error] 157-157: tsdoc-param-tag-with-invalid-type: The @param block should not include a JSDoc-style '{type}'
(tsdoc/syntax)
[error] 159-159: 'handleChangeRowsPerPage' is assigned a value but never used.
(@typescript-eslint/no-unused-vars)
[error] 170-170: tsdoc-param-tag-with-invalid-type: The @param block should not include a JSDoc-style '{type}'
(tsdoc/syntax)
[error] 182-182: tsdoc-param-tag-with-invalid-type: The @param block should not include a JSDoc-style '{type}'
(tsdoc/syntax)
[error] 196-196: 'handleSearchByBtnClick' is assigned a value but never used.
(@typescript-eslint/no-unused-vars)
src/components/OrganizationCard/OrganizationCard.spec.tsx
[error] 13-13: Delete ·
(prettier/prettier)
🪛 GitHub Actions: PR Workflow
src/components/OrganizationCard/OrganizationCard.spec.tsx
[warning] Code style issues found. File needs to be formatted using Prettier.
⏰ Context from checks skipped due to timeout of 90000ms (1)
- GitHub Check: Analyse Code With CodeQL (javascript)
🔇 Additional comments (3)
src/components/OrganizationCard/OrganizationCard.spec.tsx (2)
1-29
: LGTM! Clean transition from Jest to Vitest.The migration from Jest to Vitest is well-implemented with proper mocking setup for react-router-dom.
🧰 Tools
🪛 eslint
[error] 13-13: Delete
·
(prettier/prettier)
🪛 GitHub Actions: PR Workflow
[warning] Code style issues found. File needs to be formatted using Prettier.
31-47
: LGTM! Well-structured test data setup.The
defaultProps
object provides comprehensive test data covering all required props with realistic values.🧰 Tools
🪛 GitHub Actions: PR Workflow
[warning] Code style issues found. File needs to be formatted using Prettier.
src/screens/UserPortal/Organizations/Organizations.tsx (1)
277-277
:⚠️ Potential issueImplementation appears incomplete.
The component has several issues:
- Unused state variables:
hideDrawer
,page
,rowsPerPage
,organizations
- Unused state setter:
setMode
- Unused handlers:
handleChangeRowsPerPage
,handleSearchByBtnClick
- Empty return statement with only a placeholder comment
Please either implement the missing functionality or remove unused code.
|
||
/** | ||
* This file contains unit tests for the `OrganizationCard` component. | ||
* | ||
* The tests cover: | ||
* |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix formatting to pass pipeline checks.
Remove the whitespace from the empty line to resolve the Prettier formatting issue.
- *
+ *
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
* | |
* |
🧰 Tools
🪛 eslint
[error] 13-13: Delete ·
(prettier/prettier)
🪛 GitHub Actions: PR Workflow
[warning] Code style issues found. File needs to be formatted using Prettier.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
📜 Review details
Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
package.json
(1 hunks)
🧰 Additional context used
🪛 GitHub Actions: PR Workflow
package.json
[error] Unauthorized file modification. This file is protected and requires the 'ignore-sensitive-files-pr' label to modify or delete.
⏰ Context from checks skipped due to timeout of 90000ms (1)
- GitHub Check: Analyse Code With CodeQL (javascript)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
🔭 Outside diff range comments (1)
src/screens/UserPortal/Organizations/Organizations.tsx (1)
Line range hint
71-90
: Add error handling and loading states for data fetching.The data transformation logic lacks error handling and loading state management.
Consider adding error and loading states:
+ const [error, setError] = useState<Error | null>(null); + const [isLoading, setIsLoading] = useState(true); + useEffect(() => { + setIsLoading(true); if (data) { const orgs = data.organizationsConnection.map( // ... existing transformation ); setOrganizations(orgs); + setIsLoading(false); + } else if (error) { + setError(error); + setIsLoading(false); } - }, [data, userId]); + }, [data, error, userId]);
🧹 Nitpick comments (2)
src/components/OrganizationCard/OrganizationCard.spec.tsx (1)
171-207
: Consider using test.each for membership status testsThe membership status tests could be refactored to reduce duplication using test.each.
const membershipStatusTests = [ { status: '', expectedButton: 'joinBtn' }, { status: 'accepted', expectedButton: 'manageBtn' }, { status: 'pending', expectedButton: 'withdrawBtn' } ]; test.each(membershipStatusTests)( 'displays correct button when status is "$status"', ({ status, expectedButton }) => { render( <MockedProvider> <I18nextProvider i18n={i18nForTest}> <OrganizationCard {...defaultProps} membershipRequestStatus={status} /> </I18nextProvider> </MockedProvider> ); expect(screen.getByTestId(expectedButton)).toBeInTheDocument(); } );src/screens/UserPortal/Organizations/Organizations.tsx (1)
Line range hint
11-35
: Enhance interface documentation with property descriptions.The interface documentation should include descriptions for each property to improve code maintainability.
Add TSDoc comments for each property:
/** * Interface for the organization object. + * @property _id - Unique identifier for the organization + * @property name - Name of the organization + * @property image - URL of the organization's image + * @property description - Detailed description of the organization + * @property admins - List of organization administrators + * @property members - List of organization members + * @property address - Physical address details of the organization + * @property membershipRequestStatus - Current status of user's membership request + * @property userRegistrationRequired - Whether registration is required to join + * @property membershipRequests - List of pending membership requests */
📜 Review details
Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
src/components/OrganizationCard/OrganizationCard.spec.tsx
(1 hunks)src/screens/UserPortal/Organizations/Organizations.tsx
(4 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (1)
- GitHub Check: Test Application
🔇 Additional comments (7)
src/components/OrganizationCard/OrganizationCard.spec.tsx (5)
13-13
: Fix formatting to pass pipeline checksRemove the trailing whitespace from the empty line.
- * + *
1-29
: LGTM! Clean migration from Jest to VitestThe framework migration is well-implemented with proper async/await pattern for mocking.
31-47
: LGTM! Well-structured test dataThe defaultProps object is comprehensive and properly structured, covering all necessary fields for thorough testing.
54-81
: LGTM! Thorough visual element testingThe tests effectively verify the rendering of both image and non-image scenarios with appropriate assertions.
Also applies to: 83-98
100-144
: LGTM! Comprehensive button state testingThe tests effectively verify the correct button rendering for different membership states (empty, accepted, pending).
src/screens/UserPortal/Organizations/Organizations.tsx (2)
40-49
: Enhance component documentation with more details.The component documentation should include more details about its functionality and props.
Expand the TSDoc documentation:
/** - * Component to render the organizations of a user with pagination and filtering. + * Organizations component handles the display and management of organizations. + * It provides filtering and different view modes for all, joined, and created organizations. + * + * @remarks + * The component fetches organizations data using three different queries: + * - USER_ORGANIZATION_CONNECTION for all organizations + * - USER_JOINED_ORGANIZATIONS for joined organizations + * - USER_CREATED_ORGANIZATIONS for created organizations + * * @returns {JSX.Element} The Organizations component. */
119-130
: Verify routing implementation for the Visit button.Ensure that the routing implementation for the Visit button aligns with the application's routing system.
Run the following script to verify the routing implementation:
/> | ||
<InputGroup.Text | ||
className={`${styles.colorPrimary} ${styles.borderNone}`} | ||
style={{ cursor: 'pointer' }} | ||
onClick={handleSearchByBtnClick} | ||
data-testid="searchBtn" | ||
> | ||
<SearchOutlined className={`${styles.colorWhite}`} /> | ||
</InputGroup.Text> | ||
</InputGroup> | ||
<Dropdown drop="down-centered"> | ||
<Dropdown.Toggle | ||
className={`${styles.colorPrimary} ${styles.borderNone}`} | ||
variant="success" | ||
id="dropdown-basic" | ||
data-testid={`modeChangeBtn`} | ||
> | ||
{modes[mode]} | ||
</Dropdown.Toggle> | ||
<Dropdown.Menu> | ||
{modes.map((value, index) => { | ||
return ( | ||
<Dropdown.Item | ||
key={index} | ||
data-testid={`modeBtn${index}`} | ||
onClick={(): void => setMode(index)} | ||
> | ||
{value} | ||
</Dropdown.Item> | ||
); | ||
})} | ||
</Dropdown.Menu> | ||
</Dropdown> | ||
</div> | ||
|
||
<div | ||
className={`d-flex flex-column justify-content-between ${styles.content}`} | ||
> | ||
<div | ||
className={`d-flex flex-column ${styles.gap} ${styles.paddingY}`} | ||
> | ||
{loadingOrganizations ? ( | ||
<div className={`d-flex flex-row justify-content-center`}> | ||
<HourglassBottomIcon /> <span>Loading...</span> | ||
</div> | ||
) : ( | ||
<> | ||
{' '} | ||
{organizations && organizations.length > 0 ? ( | ||
(rowsPerPage > 0 | ||
? organizations.slice( | ||
page * rowsPerPage, | ||
page * rowsPerPage + rowsPerPage, | ||
) | ||
: /* istanbul ignore next */ | ||
organizations | ||
).map((organization: InterfaceOrganization, index) => { | ||
const cardProps: InterfaceOrganizationCardProps = { | ||
name: organization.name, | ||
image: organization.image, | ||
id: organization._id, | ||
description: organization.description, | ||
admins: organization.admins, | ||
members: organization.members, | ||
address: organization.address, | ||
membershipRequestStatus: | ||
organization.membershipRequestStatus, | ||
userRegistrationRequired: | ||
organization.userRegistrationRequired, | ||
membershipRequests: organization.membershipRequests, | ||
}; | ||
return <OrganizationCard key={index} {...cardProps} />; | ||
}) | ||
) : ( | ||
<span>{t('nothingToShow')}</span> | ||
)} | ||
</> | ||
)} | ||
</div> | ||
<table> | ||
<tbody> | ||
<tr> | ||
<PaginationList | ||
count={ | ||
/* istanbul ignore next */ | ||
organizations ? organizations.length : 0 | ||
} | ||
rowsPerPage={rowsPerPage} | ||
page={page} | ||
onPageChange={handleChangePage} | ||
onRowsPerPageChange={handleChangeRowsPerPage} | ||
/> | ||
</tr> | ||
</tbody> | ||
</table> | ||
</div> | ||
</div> | ||
</div> | ||
</> | ||
</div> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Implement the Visit button feature and enhance UI components.
The current implementation doesn't include the Visit button feature mentioned in the PR objectives and lacks proper UI components.
Consider implementing the following improvements:
return (
- <div>
+ <div className="organizations-container">
+ {isLoading ? (
+ <LoadingSpinner />
+ ) : error ? (
+ <ErrorMessage error={error} />
+ ) : organizations.length > 0 ? (
organizations.map((org) => (
- <div key={org._id}>
- <h3>{org.name}</h3>
- <p>{org.description}</p>
+ <div key={org._id} className="organization-card">
+ <div className="organization-info">
+ <h3>{org.name}</h3>
+ <p>{org.description}</p>
+ </div>
+ <button
+ className="visit-button"
+ onClick={() => window.location.href = `/organization/${org._id}`}
+ >
+ Visit
+ </button>
</div>
))
) : (
- <p>No organizations found</p>
+ <div className="empty-state">
+ <p>No organizations found</p>
+ </div>
)}
</div>
);
Committable suggestion skipped: line range outside the PR's diff.
useEffect(() => { | ||
if (mode === 0) { | ||
if (data) { | ||
const organizations = data.organizationsConnection.map( | ||
(organization: InterfaceOrganization) => { | ||
let membershipRequestStatus = ''; | ||
if ( | ||
organization.members.find( | ||
(member: { _id: string }) => member._id === userId, | ||
) | ||
) | ||
membershipRequestStatus = 'accepted'; | ||
else if ( | ||
organization.membershipRequests.find( | ||
(request: { user: { _id: string } }) => | ||
request.user._id === userId, | ||
) | ||
) | ||
membershipRequestStatus = 'pending'; | ||
return { ...organization, membershipRequestStatus }; | ||
}, | ||
); | ||
setOrganizations(organizations); | ||
} | ||
} else if (mode === 1) { | ||
if (joinedOrganizationsData && joinedOrganizationsData.users.length > 0) { | ||
const organizations = | ||
joinedOrganizationsData.users[0]?.user?.joinedOrganizations || []; | ||
setOrganizations(organizations); | ||
} | ||
} else if (mode === 2) { | ||
if ( | ||
createdOrganizationsData && | ||
createdOrganizationsData.users.length > 0 | ||
) { | ||
const organizations = | ||
createdOrganizationsData.users[0]?.appUserProfile | ||
?.createdOrganizations || []; | ||
setOrganizations(organizations); | ||
} | ||
if (joinedOrganizationsData?.users?.length > 0) { | ||
const orgs = | ||
joinedOrganizationsData.users[0]?.user?.joinedOrganizations.map( | ||
(org: InterfaceOrganization) => ({ | ||
...org, | ||
membershipRequestStatus: 'accepted', | ||
isJoined: true, | ||
}), | ||
) || []; | ||
setOrganizations(orgs); | ||
} else if (createdOrganizationsData?.users?.length > 0) { | ||
const orgs = | ||
createdOrganizationsData.users[0]?.appUserProfile?.createdOrganizations.map( | ||
(org: InterfaceOrganization) => ({ | ||
...org, | ||
membershipRequestStatus: 'accepted', | ||
isJoined: true, | ||
}), | ||
) || []; | ||
setOrganizations(orgs); | ||
} | ||
}, [mode, data, joinedOrganizationsData, createdOrganizationsData, userId]); | ||
}, [joinedOrganizationsData, createdOrganizationsData, userId]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Resolve potential state conflicts in useEffect hooks.
Multiple useEffect hooks setting the organizations state could lead to race conditions and inconsistent state updates.
Consider consolidating the data handling:
- useEffect(() => {
- if (joinedOrganizationsData?.users?.length > 0) {
- const orgs = // ... existing transformation
- setOrganizations(orgs);
- } else if (createdOrganizationsData?.users?.length > 0) {
- const orgs = // ... existing transformation
- setOrganizations(orgs);
- }
- }, [joinedOrganizationsData, createdOrganizationsData, userId]);
+ useEffect(() => {
+ const getOrganizations = () => {
+ if (joinedOrganizationsData?.users?.length > 0) {
+ return joinedOrganizationsData.users[0]?.user?.joinedOrganizations.map(
+ (org: InterfaceOrganization) => ({
+ ...org,
+ membershipRequestStatus: 'accepted',
+ isJoined: true,
+ }),
+ ) || [];
+ }
+ if (createdOrganizationsData?.users?.length > 0) {
+ return createdOrganizationsData.users[0]?.appUserProfile?.createdOrganizations.map(
+ (org: InterfaceOrganization) => ({
+ ...org,
+ membershipRequestStatus: 'accepted',
+ isJoined: true,
+ }),
+ ) || [];
+ }
+ return [];
+ };
+
+ setOrganizations(getOrganizations());
+ }, [joinedOrganizationsData, createdOrganizationsData, userId]);
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
useEffect(() => { | |
if (mode === 0) { | |
if (data) { | |
const organizations = data.organizationsConnection.map( | |
(organization: InterfaceOrganization) => { | |
let membershipRequestStatus = ''; | |
if ( | |
organization.members.find( | |
(member: { _id: string }) => member._id === userId, | |
) | |
) | |
membershipRequestStatus = 'accepted'; | |
else if ( | |
organization.membershipRequests.find( | |
(request: { user: { _id: string } }) => | |
request.user._id === userId, | |
) | |
) | |
membershipRequestStatus = 'pending'; | |
return { ...organization, membershipRequestStatus }; | |
}, | |
); | |
setOrganizations(organizations); | |
} | |
} else if (mode === 1) { | |
if (joinedOrganizationsData && joinedOrganizationsData.users.length > 0) { | |
const organizations = | |
joinedOrganizationsData.users[0]?.user?.joinedOrganizations || []; | |
setOrganizations(organizations); | |
} | |
} else if (mode === 2) { | |
if ( | |
createdOrganizationsData && | |
createdOrganizationsData.users.length > 0 | |
) { | |
const organizations = | |
createdOrganizationsData.users[0]?.appUserProfile | |
?.createdOrganizations || []; | |
setOrganizations(organizations); | |
} | |
if (joinedOrganizationsData?.users?.length > 0) { | |
const orgs = | |
joinedOrganizationsData.users[0]?.user?.joinedOrganizations.map( | |
(org: InterfaceOrganization) => ({ | |
...org, | |
membershipRequestStatus: 'accepted', | |
isJoined: true, | |
}), | |
) || []; | |
setOrganizations(orgs); | |
} else if (createdOrganizationsData?.users?.length > 0) { | |
const orgs = | |
createdOrganizationsData.users[0]?.appUserProfile?.createdOrganizations.map( | |
(org: InterfaceOrganization) => ({ | |
...org, | |
membershipRequestStatus: 'accepted', | |
isJoined: true, | |
}), | |
) || []; | |
setOrganizations(orgs); | |
} | |
}, [mode, data, joinedOrganizationsData, createdOrganizationsData, userId]); | |
}, [joinedOrganizationsData, createdOrganizationsData, userId]); | |
useEffect(() => { | |
const getOrganizations = () => { | |
if (joinedOrganizationsData?.users?.length > 0) { | |
return joinedOrganizationsData.users[0]?.user?.joinedOrganizations.map( | |
(org: InterfaceOrganization) => ({ | |
...org, | |
membershipRequestStatus: 'accepted', | |
isJoined: true, | |
}), | |
) || []; | |
} | |
if (createdOrganizationsData?.users?.length > 0) { | |
return createdOrganizationsData.users[0]?.appUserProfile?.createdOrganizations.map( | |
(org: InterfaceOrganization) => ({ | |
...org, | |
membershipRequestStatus: 'accepted', | |
isJoined: true, | |
}), | |
) || []; | |
} | |
return []; | |
}; | |
setOrganizations(getOrganizations()); | |
}, [joinedOrganizationsData, createdOrganizationsData, userId]); |
What kind of change does this PR introduce?
Feature
Issue Number:
Fixes #3162
Did you add tests for your changes?
No
Snapshots/Videos:
issue.3162.mp4
Summary
This PR introduces a 'Visit' button in the Joined Organizations filter.
Enhances the user experience by providing direct navigation to organizations from the filter.
Solves the issue of limited navigation options in the Joined Organizations section.
Does this PR introduce a breaking change?
No
Other information
The feature was tested in multiple scenarios to ensure seamless functionality.
Have you read the contributing guide?
Yes
Summary by CodeRabbit
Tests
OrganizationCard
component with comprehensive scenarios, including rendering variations and button visibility based on membership status.OrganizationTags
with better mock functions and more robust testing of user interactions.New Features
isJoined
property to track organization membership status.Bug Fixes
Chores
Organizations
component name for consistency and improved clarity.Organizations
component for enhanced user experience.