Skip to content

fix(*) send physical induction slot for mulitiple city#516

Merged
nishant22029 merged 4 commits intodevelopfrom
fix/check-multiple-cities-for-physical-induction
Nov 30, 2024
Merged

fix(*) send physical induction slot for mulitiple city#516
nishant22029 merged 4 commits intodevelopfrom
fix/check-multiple-cities-for-physical-induction

Conversation

@nishant22029
Copy link
Copy Markdown
Collaborator

@nishant22029 nishant22029 commented Nov 30, 2024

  • Added changes to check contact city and pu mulitiple induction city for physical induction

Summary by CodeRabbit

Release Notes

  • New Features

    • Enhanced logic for determining induction types based on volunteer cities.
    • Improved handling of email notifications to prevent duplicates.
    • Consolidated registration links for various volunteer activities.
    • Enhanced display of induction slots and statuses for better user experience.
  • Bug Fixes

    • Enhanced error handling and logging for induction slot generation and office contact retrieval.
    • Improved clarity in the display of induction schedules and availability.

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Nov 30, 2024

Caution

Review failed

The pull request is closed.

Walkthrough

The changes in this pull request primarily focus on enhancing the logic for volunteer induction processes within the Goonj system. Key updates include modifications to the InductionService class for determining induction types based on geographical data and refining email notification handling. Additionally, the generate_induction_slots function has been improved with better error handling and logging. The rendering of volunteer registration links has been consolidated for clarity, ensuring accurate information display based on various targets. Overall, these updates aim to streamline the induction process and improve the user experience.

Changes

File Path Change Summary
wp-content/civi-extensions/goonjcustom/Civi/InductionService.php Updated fetchTypeOfInduction to include logic for induction cities; refined createInduction and sendInductionEmail for better checks and logging.
wp-content/plugins/goonj-blocks/build/functions.php Enhanced generate_induction_slots with improved error handling and logging; refined logic for generating induction slots based on office contacts.
wp-content/plugins/goonj-blocks/build/render.php Improved handling of volunteer registration links and induction slots display; added error handling for DateTime objects.
wp-content/plugins/goonj-blocks/src/functions.php Modified generate_induction_slots for better validation and city handling; refined logic for slot generation based on contact city.

Possibly related PRs

Suggested labels

status : ready for review

Suggested reviewers

  • tarunnjoshi

🎉 In the realm of Goonj, changes abound,
Induction slots and emails, all tightly wound.
With cities checked and logs in place,
Volunteers now find a smoother space.
So here's to the code, refined and bright,
Making induction a pure delight! 🎉

Warning

Rate limit exceeded

@nishant22029 has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 19 minutes and 19 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between 08af764 and 422f6b5.


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 08af764 and 422f6b5.

📒 Files selected for processing (3)
  • wp-content/civi-extensions/goonjcustom/Civi/InductionService.php (1 hunks)
  • wp-content/plugins/goonj-blocks/build/functions.php (1 hunks)
  • wp-content/plugins/goonj-blocks/src/functions.php (1 hunks)

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?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

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)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@nishant22029 nishant22029 self-assigned this Nov 30, 2024
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a 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 and nitpick comments (11)
wp-content/plugins/goonj-blocks/src/functions.php (3)

102-102: Add validation for city format in database query

The query selects city data but doesn't ensure consistent formatting. Consider adding a SQL-level formatting function.

-            ->addSelect('id', 'display_name', 'Goonj_Office_Details.Other_Induction_Cities', 'address_primary.city')
+            ->addSelect('id', 'display_name', 'Goonj_Office_Details.Other_Induction_Cities', 
+                'LOWER(TRIM(address_primary.city)) as address_primary_city')

119-123: Optimize city array operations

The current implementation performs multiple array operations that could be combined for better efficiency.

-                $otherCities = array_map('trim', explode(',', $officeContactData['Goonj_Office_Details.Other_Induction_Cities']));
-                $officeContactInductionCities = array_merge($officeContactInductionCities, $otherCities);
+                $officeContactInductionCities = array_merge(
+                    $officeContactInductionCities,
+                    array_filter(array_map('trim', explode(',', $officeContactData['Goonj_Office_Details.Other_Induction_Cities'])))
+                );

107-129: Add documentation for city handling logic

The city handling logic is complex and lacks documentation explaining the business rules and edge cases.

Add PHPDoc comments explaining:

  1. The purpose of the $officeContactInductionCities array
  2. The city formatting rules
  3. How duplicates are handled
  4. The significance of primary vs other induction cities
wp-content/plugins/goonj-blocks/build/functions.php (4)

108-110: Remove duplicate initialization of $officeContactInductionCities

The variable $officeContactInductionCities is initialized twice without any operations in between. This redundancy can be removed to streamline the code.

Apply this diff to remove the redundant line:

108   $officeContactInductionCities = [];

110 - $officeContactInductionCities = [];

105-105: Eliminate commented-out code for cleaner codebase

The commented-out line at line 105 is no longer in use. Removing unused code helps in keeping the codebase clean and maintainable.

Apply this diff to remove the commented-out line:

105 - // ->addWhere('address_primary.city', 'LIKE', $contactCityFormatted . '%')

113-133: Refactor induction cities extraction into a separate function

The block of code from lines 113 to 133 is responsible for extracting and processing induction cities from $officeContactData. To adhere to the single responsibility principle and enhance readability, consider moving this logic into a dedicated function.

This refactoring will make the main function cleaner and the code easier to test and maintain.


150-150: Remove obsolete commented-out code

The commented-out return statement at line 150 appears to be outdated and unnecessary. Eliminating such code reduces clutter and potential confusion.

Apply this diff to remove the unused code:

150 - // return generate_slots($assignedOfficeId, $defaultMaxSlot, $physicalInductionType, $inductionSlotStartDate);
wp-content/civi-extensions/goonjcustom/Civi/InductionService.php (4)

835-856: Extract Logic into a Separate Method for Clarity

The block of code responsible for collecting induction cities from office contacts is sizable and could be extracted into its own method. This adheres to the Single Responsibility Principle and improves code readability.

Consider extracting the code into a method like getOfficeContactInductionCities($officeContact) and then call this method within fetchTypeOfInduction.


864-869: Simplify Induction Type Determination Logic

The current else block redundantly assigns $inductionType = 'Online' even though it's not needed. Since the variable is already set to 'Online' if the condition isn't met, you can streamline this part of the code for better readability.

Apply this diff to simplify the logic:

if (in_array(strtolower($contactCityFormatted), $officeContactInductionCities)) {
    return $inductionType;
} else {
-    $inductionType = 'Online';
    return 'Online';
}

828-869: Avoid Deep Nesting and Improve Readability

The method fetchTypeOfInduction contains deep nesting, making it harder to read and maintain. Consider refactoring the code to reduce nesting levels, possibly by using early returns or breaking down the code into smaller methods.

For example:

if ($officeContact->count() === 0) {
    return 'Online';
}

// Proceed with processing since offices exist

This approach enhances code clarity by handling exceptional cases early.


828-869: Add Comments to Explain Complex Logic

The logic within fetchTypeOfInduction is non-trivial. Adding explanatory comments or docstrings will help other developers understand the purpose and functionality of the code, improving maintainability.

Consider adding comments that describe the steps involved in determining the induction type based on state and city.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 2621567 and 52d29be.

📒 Files selected for processing (4)
  • wp-content/civi-extensions/goonjcustom/Civi/InductionService.php (1 hunks)
  • wp-content/plugins/goonj-blocks/build/functions.php (1 hunks)
  • wp-content/plugins/goonj-blocks/build/render.php (0 hunks)
  • wp-content/plugins/goonj-blocks/src/functions.php (1 hunks)
💤 Files with no reviewable changes (1)
  • wp-content/plugins/goonj-blocks/build/render.php
🔇 Additional comments (1)
wp-content/plugins/goonj-blocks/src/functions.php (1)

102-140: Verify consistent city handling across codebase

Let's ensure that city comparisons and formatting are consistent across the codebase.

✅ Verification successful

City handling looks consistent with best practices

The code follows consistent patterns for city handling:

  • Uses array_merge() to combine primary and other induction cities
  • Applies strtolower() for case-insensitive city comparisons
  • Properly handles array operations with array_unique() and array_values()
  • Validates city existence before access
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for city comparisons and formatting in PHP files
echo "Searching for city comparisons..."
rg -t php "(?i)(city.*=|=.*city|\bcity\b.*comparison)" -A 3 -B 3

echo "Searching for array operations on cities..."
rg -t php "(?i)(explode.*city|array_map.*city|array_merge.*city)" -A 3 -B 3

echo "Checking for potential case sensitivity issues..."
rg -t php "(?i)(strtolower.*city|strtoupper.*city)" -A 3 -B 3

Length of output: 154401

Comment on lines +136 to +140
if (in_array(strtolower($contactCityFormatted), $officeContactInductionCities)) {
return generate_slots($assignedOfficeId, $defaultMaxSlot, $physicalInductionType, $inductionSlotStartDate);
} else {
return generate_slots($assignedOfficeId, $defaultMaxSlot, $onlineInductionType, $inductionSlotStartDate);
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Improve induction type determination logic

The current implementation has several potential issues:

  1. Case sensitivity in city comparison could cause bugs
  2. Missing logging for debugging induction type decisions
  3. Complex nested conditions
-        if (in_array(strtolower($contactCityFormatted), $officeContactInductionCities)) {
-            return generate_slots($assignedOfficeId, $defaultMaxSlot, $physicalInductionType, $inductionSlotStartDate);
-        } else {
-            return generate_slots($assignedOfficeId, $defaultMaxSlot, $onlineInductionType, $inductionSlotStartDate);
-        }        
+        $inductionType = in_array(strtolower($contactCityFormatted), $officeContactInductionCities)
+            ? $physicalInductionType
+            : $onlineInductionType;
+        
+        \Civi::log()->info('Determined induction type', [
+            'city' => $contactCityFormatted,
+            'type' => $inductionType,
+            'availableCities' => $officeContactInductionCities
+        ]);
+        
+        return generate_slots($assignedOfficeId, $defaultMaxSlot, $inductionType, $inductionSlotStartDate);
📝 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.

Suggested change
if (in_array(strtolower($contactCityFormatted), $officeContactInductionCities)) {
return generate_slots($assignedOfficeId, $defaultMaxSlot, $physicalInductionType, $inductionSlotStartDate);
} else {
return generate_slots($assignedOfficeId, $defaultMaxSlot, $onlineInductionType, $inductionSlotStartDate);
}
$inductionType = in_array(strtolower($contactCityFormatted), $officeContactInductionCities)
? $physicalInductionType
: $onlineInductionType;
\Civi::log()->info('Determined induction type', [
'city' => $contactCityFormatted,
'type' => $inductionType,
'availableCities' => $officeContactInductionCities
]);
return generate_slots($assignedOfficeId, $defaultMaxSlot, $inductionType, $inductionSlotStartDate);

Comment on lines +836 to +856
if ($officeContact->count() > 0) {
// Extract the first row (assuming one result, based on rowCount => 1)
$officeContactData = $officeContact[0];

// Add the primary city to the array
if (!empty($officeContactData['address_primary.city'])) {
$officeContactInductionCities[] = $officeContactData['address_primary.city'];
}

// Add the other induction cities to the array
if (!empty($officeContactData['Goonj_Office_Details.Other_Induction_Cities'])) {
// Split the string into an array and merge it
$otherCities = array_map('trim', explode(',', $officeContactData['Goonj_Office_Details.Other_Induction_Cities']));
$officeContactInductionCities = array_merge($officeContactInductionCities, $otherCities);
}

// Convert all cities to lowercase, remove duplicates, and re-index the array
$officeContactInductionCities = array_map('strtolower', $officeContactInductionCities);
$officeContactInductionCities = array_unique($officeContactInductionCities);
$officeContactInductionCities = array_values($officeContactInductionCities);
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Refactor to Handle Multiple Offices and Avoid Assumptions

The current implementation assumes only one Goonj office per state by directly accessing $officeContact[0]. This assumption could lead to issues if multiple offices exist in the same state. To enhance scalability and maintainability, consider iterating over all matching offices to gather induction cities.

Apply this diff to handle multiple offices:

-// Extract the first row (assuming one result, based on rowCount => 1)
-$officeContactData = $officeContact[0];
-
-// Add the primary city to the array
-if (!empty($officeContactData['address_primary.city'])) {
-    $officeContactInductionCities[] = $officeContactData['address_primary.city'];
-}
-
-// Add the other induction cities to the array
-if (!empty($officeContactData['Goonj_Office_Details.Other_Induction_Cities'])) {
-    // Split the string into an array and merge it
-    $otherCities = array_map('trim', explode(',', $officeContactData['Goonj_Office_Details.Other_Induction_Cities']));
-    $officeContactInductionCities = array_merge($officeContactInductionCities, $otherCities);
-}
-
-// Convert all cities to lowercase, remove duplicates, and re-index the array
-$officeContactInductionCities = array_map('strtolower', $officeContactInductionCities);
-$officeContactInductionCities = array_unique($officeContactInductionCities);
-$officeContactInductionCities = array_values($officeContactInductionCities);
+// Iterate over each office to collect induction cities
+foreach ($officeContact as $officeContactData) {
+    // Add the primary city to the array
+    if (!empty($officeContactData['address_primary.city'])) {
+        $officeContactInductionCities[] = $officeContactData['address_primary.city'];
+    }
+
+    // Add the other induction cities to the array
+    if (!empty($officeContactData['Goonj_Office_Details.Other_Induction_Cities'])) {
+        // Split the string into an array and merge it
+        $otherCities = array_map('trim', explode(',', $officeContactData['Goonj_Office_Details.Other_Induction_Cities']));
+        $officeContactInductionCities = array_merge($officeContactInductionCities, $otherCities);
+    }
+}
+
+// Normalize the induction cities array
+$officeContactInductionCities = array_map('strtolower', $officeContactInductionCities);
+$officeContactInductionCities = array_unique($officeContactInductionCities);
+$officeContactInductionCities = array_values($officeContactInductionCities);
📝 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.

Suggested change
if ($officeContact->count() > 0) {
// Extract the first row (assuming one result, based on rowCount => 1)
$officeContactData = $officeContact[0];
// Add the primary city to the array
if (!empty($officeContactData['address_primary.city'])) {
$officeContactInductionCities[] = $officeContactData['address_primary.city'];
}
// Add the other induction cities to the array
if (!empty($officeContactData['Goonj_Office_Details.Other_Induction_Cities'])) {
// Split the string into an array and merge it
$otherCities = array_map('trim', explode(',', $officeContactData['Goonj_Office_Details.Other_Induction_Cities']));
$officeContactInductionCities = array_merge($officeContactInductionCities, $otherCities);
}
// Convert all cities to lowercase, remove duplicates, and re-index the array
$officeContactInductionCities = array_map('strtolower', $officeContactInductionCities);
$officeContactInductionCities = array_unique($officeContactInductionCities);
$officeContactInductionCities = array_values($officeContactInductionCities);
}
if ($officeContact->count() > 0) {
// Iterate over each office to collect induction cities
foreach ($officeContact as $officeContactData) {
// Add the primary city to the array
if (!empty($officeContactData['address_primary.city'])) {
$officeContactInductionCities[] = $officeContactData['address_primary.city'];
}
// Add the other induction cities to the array
if (!empty($officeContactData['Goonj_Office_Details.Other_Induction_Cities'])) {
// Split the string into an array and merge it
$otherCities = array_map('trim', explode(',', $officeContactData['Goonj_Office_Details.Other_Induction_Cities']));
$officeContactInductionCities = array_merge($officeContactInductionCities, $otherCities);
}
}
// Normalize the induction cities array
$officeContactInductionCities = array_map('strtolower', $officeContactInductionCities);
$officeContactInductionCities = array_unique($officeContactInductionCities);
$officeContactInductionCities = array_values($officeContactInductionCities);
}

->addWhere('contact_sub_type', 'CONTAINS', 'Goonj_Office')
->addWhere('address_primary.state_province_id', '=', $contactStateId)
->addWhere('address_primary.city', 'LIKE', $contactCityFormatted . '%')
// ->addWhere('address_primary.city', 'LIKE', $contactCityFormatted . '%')
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we don't need it can we remove it

->addWhere('address_primary.city', 'LIKE', $contactCityFormatted . '%')
// ->addWhere('address_primary.city', 'LIKE', $contactCityFormatted . '%')
->execute();
\Civi::log()->info('officeContact', ['officeContact'=>$officeContact]);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why we need this

Comment on lines +108 to +110
$officeContactInductionCities = [];

if ($officeContact->count() === 0) {
$officeContactInductionCities = [];
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why we need these two with same variable name?

// Check if the result has any rows
if ($officeContact->count() > 0) {
// Extract the first row (assuming one result, based on rowCount => 1)
$officeContactData = $officeContact[0];
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if we have more multiple offices exist in the same state

Comment on lines +135 to +137
// Log the result for debugging
\Civi::log()->info('officeContactInductionCities', ['officeContactInductionCities' => $officeContactInductionCities, 'contactCityFormatted'=>$contactCityFormatted]);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need debugging now? Do we know that we were getting any error?

Comment on lines +138 to +139


Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove extra line

}
// generate physical induction slots having office in their states
return generate_slots($assignedOfficeId, $defaultMaxSlot, $physicalInductionType, $inductionSlotStartDate);
// return generate_slots($assignedOfficeId, $defaultMaxSlot, $physicalInductionType, $inductionSlotStartDate);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we dont need it, please remove it

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants