Skip to content

Added service file and redirections for diffrent button in events#678

Closed
nishant22029 wants to merge 27 commits intodevelopfrom
feat/goonj-initiated-events
Closed

Added service file and redirections for diffrent button in events#678
nishant22029 wants to merge 27 commits intodevelopfrom
feat/goonj-initiated-events

Conversation

@nishant22029
Copy link
Copy Markdown
Collaborator

@nishant22029 nishant22029 commented Dec 23, 2024

  • Added hook to generate qr code when event qr not exists
  • Added cron job to send outcome mail to goonj poc's
  • Added changes to redirect to material contribution and individual registration page of contact not exists

Summary by CodeRabbit

  • New Features

    • Introduced support for event-related data, including new sections for event details such as start time, end time, and address.
    • Added functionality to handle event material contributions and links for donations and registrations.
    • Implemented a cron job for managing initiated events and sending outcome emails.
    • Enhanced user identification and registration processes related to events.
    • Added new event handlers for processing form submissions related to institution registration.
  • Bug Fixes

    • Improved address formatting for events to enhance clarity and presentation.
    • Corrected logical conditions in group assignment methods to improve robustness.
  • Chores

    • Updated logging for better tracking of event data processing.
    • Enhanced visibility control of form elements for improved user experience.
    • Added styles for form elements to improve layout and responsiveness.

@nishant22029 nishant22029 self-assigned this Dec 23, 2024
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Dec 23, 2024

Walkthrough

This pull request introduces event-related functionality to the Goonj Blocks WordPress plugin. The changes span across multiple files in the plugin, primarily focusing on adding support for 'events' as a new target type. The modifications include updating rendering logic, expanding API interactions, and introducing new data structures to handle event-specific information such as start time, end time, address, and contribution links.

Changes

File Change Summary
wp-content/plugins/goonj-blocks/build/render.php Added 'events' to $headings and $target_data arrays; Updated conditional checks to process event targets; Modified address rendering logic for events.
wp-content/plugins/goonj-blocks/goonj-blocks.php Introduced 'events' action type in gb_goonj_blocks_check_action_target_exists() function; Added CiviCRM API event data retrieval and logging for event processing.
wp-content/plugins/goonj-blocks/src/render.php Similar updates to build/render.php; Added event material contribution link and updated address rendering logic.
wp-content/civi-extensions/goonjcustom/Civi/GoonjInitiatedEventsService.php Introduced GoonjInitiatedEventsService class for event email notifications and QR code generation; Added methods for handling event outcomes and subscriptions.
wp-content/civi-extensions/goonjcustom/api/v3/Goonjcustom/GoonjInitiatedEventsCron.php Added cron job functionality to handle initiated events and send outcome emails; Implemented error handling and logging.
wp-content/themes/goonj-crm/functions.php Modified user identification logic to include 'event-material-contribution'; Updated redirection logic for individual registrations.
wp-content/themes/goonj-crm/templates/form-check-user.php Updated email requirement logic to include 'event-material-contribution'.
wp-content/themes/goonj-crm/assets/styles/goonj-main.scss Added CSS rules to hide specific form elements based on their position.
wp-content/themes/goonj-crm/style.css Added styles for form elements, ensuring responsive layout and visibility management.
wp-content/civi-extensions/goonjcustom/templates/CRM/Goonjcustom/Tabs/Events.tpl Introduced AngularJS component structure for dynamic rendering of event-related forms.

Possibly related PRs

Suggested labels

status : ready for review

Suggested reviewers

  • tarunnjoshi

Poem

🎉 Events arise, a digital dance
Code weaves magic with each new glance
Blocks transform, CiviCRM's embrace
Goonj's platform finds its grace
Rendering dreams, one line at a time! 🚀


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 generate docstrings to generate docstrings for this PR. (Beta)
  • @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.

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: 0

🧹 Nitpick comments (8)
wp-content/plugins/goonj-blocks/goonj-blocks.php (1)

159-159: Remove or reconsider excessive logging
While logging is beneficial for debugging, logging entire data objects in production can clutter logs and potentially reveal sensitive info. Please make sure redaction or care is in place if personal data is included.

wp-content/plugins/goonj-blocks/build/render.php (4)

84-89: Potential cross-file duplication for $event_material_contribution_link
You introduced an $event_material_contribution_link that mirrors existing pattern setups, which is good for consistency. However, there is some duplication in both build/render.php and src/render.php. Consider extracting these repeated link-building statements to a helper function or method to adhere to the DRY (Don’t Repeat Yourself) principle.

- $event_material_contribution_link = sprintf(
-     '/events-contribution-verification/?source=%s&target_id=%s',
-     $action_target['title'],
-     $action_target['id'],
- );
...
+ // Example approach: 
+ $event_material_contribution_link = gb_generate_link('events-contribution-verification', $action_target);

215-223: New 'events' target data
Including 'events' in $target_data with start/end times and addresses is aligned with how other entities are handled. However, the sample label for 'events' is "Address of the camp," which may be misleading if these are not strictly "camps." Consider a more neutral label, like "Address of the Event."

- 'address_label' => 'Address of the camp',
+ 'address_label' => 'Address of the event',

226-226: Expanded if-condition for 'events'
Including 'events' in the condition ensures the code below processes event data. Keep an eye on the complexity of this condition. If you keep adding more targets, you might want to consider a more modular approach or a switch statement.


278-286: Address rendering for 'events'
You're correctly switching to CRM_Utils_Address::format for 'events'. Make sure you handle the scenario when $address is null or missing fields—particularly if the event does not have a defined primary address.

if ($target === 'events' && !empty($address)) {
    echo CRM_Utils_Address::format($address);
} else {
    echo esc_html($address);
}
wp-content/plugins/goonj-blocks/src/render.php (3)

84-89: Duplication of link-building logic
As noted in build/render.php, this link-building code is also repeated. Consider creating a shared helper function for consistency and easier maintenance.


215-223: Embedding 'events' in $target_data
Equivalent to the changes in build/render.php. Same suggestion applies regarding “Address of the event” label.


278-286: Address rendering for 'events'
Fine approach. As recommended for build/render.php, consider safe-checking that the $address isn’t empty.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0631868 and b145f4f.

📒 Files selected for processing (3)
  • wp-content/plugins/goonj-blocks/build/render.php (5 hunks)
  • wp-content/plugins/goonj-blocks/goonj-blocks.php (2 hunks)
  • wp-content/plugins/goonj-blocks/src/render.php (5 hunks)
🔇 Additional comments (7)
wp-content/plugins/goonj-blocks/goonj-blocks.php (2)

34-34: Add 'events' action to rewrite rules
The inclusion of 'events' here is good for ensuring that the custom rewrite rule will handle the /actions/events/ route properly. However, consider clarifying the naming conventions or ensure you have consistent coverage of other event-related routes if you want granular route handling, such as indexing or other detail pages.


163-187: New 'events' case
This block correctly retrieves the event data and associated primary address, then sets it on the global query object. The approach is consistent with other action types. Consider adding more robust error handling (e.g., if the address is missing).

wp-content/plugins/goonj-blocks/build/render.php (2)

28-29: Introduction of 'events' heading
Adding 'events' to the $headings array ensures the UI properly labels event pages. This is consistent with your approach for other types.


262-262: Inclusion of 'events' in date/time row
Expanding the same date/time UI sections for 'events' maintains consistency. Ensure correct date/time formatting if event date/time fields differ from the other targets.

✅ Verification successful

Let me gather more information about the date/time UI sections and their implementation across different targets.


Date/time formatting for events is properly implemented

Based on the code analysis, the 'events' target is correctly integrated into the date/time UI sections with proper field mappings:

  • Uses consistent date/time fields: 'start_date' and 'end_date'
  • Shares the same date/time formatting functions: gb_format_date() and gb_format_time_range()
  • Follows the same UI structure as other targets in the conditional block

The only difference is in address formatting where events use CRM_Utils_Address::format() instead of esc_html(), which is an intentional distinction.

🏁 Scripts executed

The following scripts were executed for the analysis:

Error: No shell scripts found


Script:

#!/bin/bash
# Search for date/time related code sections in render.php
rg -B 5 -A 10 "date|time" wp-content/plugins/goonj-blocks/build/render.php

# Look for event-specific date/time field implementations
rg -B 3 -A 3 "events.*date|events.*time" wp-content/plugins/goonj-blocks/build/render.php

# Search for the complete conditional block structure
rg -B 2 -A 10 "\$target === '(collection-camp|institution-collection-camp|goonj-activities|institution-goonj-activities|events)'" wp-content/plugins/goonj-blocks/build/render.php

Length of output: 8463

wp-content/plugins/goonj-blocks/src/render.php (3)

28-29: 'events' heading
Same feedback as build/render.php: good introduction of the label "Goonj Events."


226-226: Conditional inclusion of 'events'
Same feedback: it’s correct to expand the if-condition to handle 'events'; watch out for future expansions.


262-262: Add 'events' to the date/time logic
Same as build/render.php. Confirm date/time are accurately retrieved from the needed event fields.

✅ Verification successful

Let me search for the date/time logic implementation to verify if it properly handles the 'events' target.


Let me try to find the date/time logic for events in the codebase.


Date/time fields for events are properly handled
Based on the code inspection, the date/time logic for 'events' target is correctly implemented:

  1. The 'events' target is included in the conditional block that handles date/time display
  2. The date/time fields are properly mapped in the target_data array:
    • 'start_time' => 'start_date'
    • 'end_time' => 'end_date'
  3. The values are formatted consistently using the same functions as other targets:
    • gb_format_date() for start and end dates
    • gb_format_time_range() for time display
🏁 Scripts executed

The following scripts were executed for the analysis:

Error: No shell scripts found


Script:

#!/bin/bash
# Search for date/time related code in render.php files
rg -A 10 "date|time" --type php "render.php$"

Length of output: 99


Script:

#!/bin/bash
# Search for event-related date/time handling
rg -A 10 "events.*date|events.*time" --type php

Length of output: 43651


Script:

#!/bin/bash
# Look for the complete conditional block containing date/time logic
rg -B 5 -A 15 "\$target === '(collection-camp|institution-collection-camp|goonj-activities|institution-goonj-activities|events)'" --type php

Length of output: 147


Script:

#!/bin/bash
# Search for the file content around the target condition
rg -B 10 -A 20 "target === 'collection-camp'" wp-content/plugins/goonj-blocks/src/render.php

Length of output: 1942


Script:

#!/bin/bash
# Look for date/time related code in the render.php file
rg -B 5 -A 10 "date|time" wp-content/plugins/goonj-blocks/src/render.php

Length of output: 8183


Script:

#!/bin/bash
# Search for event-related fields and their handling
rg -B 5 -A 10 "events.*field|event.*date|event.*time" wp-content/plugins/goonj-blocks/src/

Length of output: 92

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: 5

🧹 Nitpick comments (4)
wp-content/civi-extensions/goonjcustom/Civi/GoonjInitiatedEventsService.php (1)

91-95: Grammatical error in email body.
The text “Their is one forms that require your attention…” is grammatically incorrect. Rework to ensure clarity.

Suggested refactor:

- <p>Thank you for attending the goonj activity <strong>$eventId</strong> at <strong>$eventAddress</strong>. Their is one forms that require your attention...
+ <p>Thank you for attending the goonj activity <strong>$eventId</strong> at <strong>$eventAddress</strong>. There is one form requiring your attention...
wp-content/themes/goonj-crm/templates/form-check-user.php (1)

12-12: Consider centralizing the “purposes not requiring email” array.
The addition of 'event-material-contribution' here is valid, but the same array is repeated in multiple places in the codebase. Centralizing this list in a single configuration or constant would help maintain consistency and avoid mistakes when adding or removing entries in the future.

wp-content/themes/goonj-crm/functions.php (2)

150-150: Avoid repeating “email not required” logic in multiple locations.
This array is defined here and in “form-check-user.php” (line 12). Consider storing it in a single location (e.g., a config file, global constants, or a helper function) to eliminate duplication.


326-335: Validate newly introduced case for ‘event-material-contribution’.
This new switch case for ‘event-material-contribution’ follows the existing pattern. However, consider extracting common logic (e.g., building URLs with shared parameters) into a reusable function to reduce potential duplication across different cases.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b145f4f and 9fac744.

📒 Files selected for processing (4)
  • wp-content/civi-extensions/goonjcustom/Civi/GoonjInitiatedEventsService.php (1 hunks)
  • wp-content/civi-extensions/goonjcustom/api/v3/Goonjcustom/GoonjInitiatedEventsCron.php (1 hunks)
  • wp-content/themes/goonj-crm/functions.php (4 hunks)
  • wp-content/themes/goonj-crm/templates/form-check-user.php (1 hunks)
🔇 Additional comments (1)
wp-content/themes/goonj-crm/functions.php (1)

428-438: Ensure consistent handling of event-based flows for existing contacts.
These lines effectively redirect existing contacts to the new events material contribution form. The logic is consistent with other contribution flows. However, stay vigilant for potential differences or additional parameters unique to events that might require special handling.

Comment on lines +11 to +14
* Goonjcustom.GoonjActivitiesCampCron API specification (optional)
* This is used for documentation and validation.
*
* @param array $spec
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

DocBlock naming mismatch.
The docblock references "GoonjActivitiesCampCron" but the actual function is named "goonj_initiated_events_cron". This might cause confusion for future maintainers and potential API consumers.

Comment on lines +54 to +58
\Civi::log()->info('Error Goonj Activities Cron', [
'id' => $camp['id'],
'error' => $e->getMessage(),
]);
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue

Undefined variable $camp.
Inside the catch block, the code references $camp['id'] even though $camp is not defined. It’s likely intended to reference $event['id'].

Suggested fix:

- 'id' => $camp['id'],
+ 'id' => $event['id'],
📝 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
\Civi::log()->info('Error Goonj Activities Cron', [
'id' => $camp['id'],
'error' => $e->getMessage(),
]);
}
\Civi::log()->info('Error Goonj Activities Cron', [
'id' => $event['id'],
'error' => $e->getMessage(),
]);
}

Comment on lines +77 to +78
\Civi::log()->error("Error in sendLogisticsEmail for $campId " . $e->getMessage());
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue

Undefined variable $campId.
In the exception message, '$campId' is referenced, but there's no variable named $campId in this scope. Consider replacing it with $eventId or removing it if it's not needed.

Suggested fix:

- \Civi::log()->error("Error in sendLogisticsEmail for $campId " . $e->getMessage());
+ \Civi::log()->error("Error in sendLogisticsEmail for $eventId " . $e->getMessage());
📝 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
\Civi::log()->error("Error in sendLogisticsEmail for $campId " . $e->getMessage());
}
\Civi::log()->error("Error in sendLogisticsEmail for $eventId " . $e->getMessage());
}

Comment on lines +88 to +95
$campOutcomeFormUrl = $homeUrl . 'goonj-initiated-events-outcome/#?Event1=' . $eventId . '&Goonj_Events_Outcome.Filled_By=' . $campAttendedById;

$html = "
<p>Dear $attendeeName,</p>
<p>Thank you for attending the goonj activity <strong>$eventId</strong> at <strong>$eventAddress</strong>. Their is one forms that require your attention during and after the goonj activity:</p>
<ol>
Please complete this form from the goonj activity location once the goonj activity ends.</li>
<li><a href=\"$campOutcomeFormUrl\">Goonj Activity Outcome Form</a><br>
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue

Inconsistent variable name used in URL.
The query parameter is "…&Goonj_Events_Outcome.Filled_By=' . $campAttendedById", while the variable is named $eventAttendedById. This mismatch can cause confusion or incorrect parameter usage.

Suggested fix:

- $campOutcomeFormUrl = $homeUrl . 'goonj-initiated-events-outcome/#?Event1=' . $eventId . '&Goonj_Events_Outcome.Filled_By=' . $campAttendedById;
+ $campOutcomeFormUrl = $homeUrl . 'goonj-initiated-events-outcome/#?Event1=' . $eventId . '&Goonj_Events_Outcome.Filled_By=' . $eventAttendedById;

Committable suggestion skipped: line range outside the PR's diff.

Comment on lines +689 to +699
case 'event-material-contribution':
$sourceProcessingCenter = $individual['Individual_fields.Source_Processing_Center'];
$events = \Civi\Api4\Event::get(TRUE)
->addWhere('title', '=', $source)
->execute()->first();
$redirectPath = sprintf(
'/events-material-contribution/#?Material_Contribution.Event=%s&source_contact_id=%s',
$events['id'],
$individual['id']
);
break;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codebase verification

Add null check before accessing event ID in the redirect path

The codebase shows a pattern where first() results are consistently checked with !empty() before accessing their properties, but this pattern is missing in the event-material-contribution case. This could lead to a PHP error if no matching event is found.

  • In wp-content/themes/goonj-crm/functions.php, add a null check before using $events['id'] in the redirect path, similar to other cases in the same file:
if (!empty($events['id'])) {
    $redirectPath = sprintf(
        '/events-material-contribution/#?Material_Contribution.Event=%s&source_contact_id=%s',
        $events['id'],
        $individual['id']
    );
} else {
    // Handle the case where no matching event is found
    $redirectPath = '/events-material-contribution/';
}
🔗 Analysis chain

Check for possible multiple or missing Event records when redirecting.
The code assumes a single match for the event title. If multiple events share the same title or if none is found, this block could fail. To mitigate this risk, consider verifying the query result count or implementing a fallback if the event is not found.


Let me verify this by checking the codebase for similar event title handling patterns and potential error handling mechanisms.

This will help us understand:

  1. How event queries are typically handled in the codebase
  2. Whether there's existing error handling for similar scenarios
  3. Common patterns for dealing with potential multiple or missing results

Let me analyze the results to provide a concrete recommendation.


Let me try a different search strategy to find Event query patterns.

This should help us:

  1. Locate files that use Event queries
  2. Understand how first() results are typically handled in the codebase
  3. Identify if there are any error handling patterns we should follow

Let me try one final search to find the error handling patterns around Event queries.

This should help us understand:

  1. How Event queries are structured in the relevant files
  2. Whether there's any error handling around execute()->first() calls
  3. Common patterns for handling potential null results
🏁 Scripts executed

The following scripts were executed for the analysis:

Error: No shell scripts found


Script:

#!/bin/bash
# Search for Event::get usage patterns to understand how events are typically queried
ast-grep --pattern 'Event::get($$$)->addWhere($$$)->execute()'

# Search for error handling patterns around Event queries
rg -B 2 -A 2 "Event::get.*execute" 

Length of output: 9336


Script:

#!/bin/bash
# Search for Event query patterns using ripgrep
rg -l "\\\\Civi\\\\Api4\\\\Event::get" 

# Then search for first() usage patterns
rg -B 3 -A 3 "->first\(\)" 

Length of output: 966


Script:

#!/bin/bash
# Search for Event query patterns in the identified files
rg -A 5 "Event::get" wp-content/themes/goonj-crm/functions.php wp-content/plugins/goonj-blocks/goonj-blocks.php

# Search for error handling around execute()
rg -B 2 -A 2 "execute\(\)->first" wp-content/themes/goonj-crm/functions.php wp-content/plugins/goonj-blocks/goonj-blocks.php

Length of output: 3252

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: 1

🧹 Nitpick comments (4)
wp-content/themes/goonj-crm/assets/styles/goonj-main.scss (1)

Line range hint 1-400: Improve maintainability with SCSS best practices

The file has several maintainability concerns that should be addressed:

  1. Excessive nesting (up to 8 levels deep) makes the code harder to read and maintain
  2. Heavy use of !important indicates specificity issues
  3. Repeated declarations for font-family, padding, margins, etc.
  4. Long, specific selectors that are brittle and hard to maintain

Consider these improvements:

  1. Limit nesting to 3-4 levels max
  2. Extract common styles into reusable classes or mixins
  3. Use BEM naming to reduce specificity and eliminate need for !important
  4. Create variables for common values:
// Variables
$font-family-base: "Open Sans", sans-serif;
$border-radius: 4px;
$spacing-unit: 8px;

// Mixins for common styles
@mixin form-input {
  border: 1px solid rgba(0, 0, 0, 0.3);
  border-radius: $border-radius;
  padding: $spacing-unit;
  background-image: none;
}

@mixin base-text {
  font-family: $font-family-base;
  line-height: 16px;
}

// Example BEM structure
.crm-form {
  &__fieldset {
    border-top: none;
  }
  
  &__input {
    @include form-input;
  }
  
  &__label {
    @include base-text;
    text-align: justify;
    width: 50%;
  }
}

This would make the code more maintainable and easier to update.

wp-content/civi-extensions/goonjcustom/Civi/GoonjInitiatedEventsService.php (2)

31-82: Consider Splitting Method Logic

The sendEventOutcomeEmail method handles both retrieval of contact info and sending mail, as well as updating the event. Splitting it into smaller dedicated methods (e.g., retrieving contact info, constructing mail parameters, sending mail, and updating the event) will make it more readable and maintainable.


256-319: Tabset Configuration for Material Contributions

The new method goonjActivitiesTabset handles adding a custom tab for “Material Contributions.” The approach of checking permissions and injecting AngularJS modules is clear. Please confirm the intended user roles have the correct permission sets to see the new tab.

wp-content/themes/goonj-crm/style.css (1)

15-15: Avoid Overriding Background Shorthand After background-image

Static analysis indicates an unexpected shorthand property "background" after "background-image:none". For clarity and maintainability, consider removing or merging duplicative properties to avoid overrides that could cause confusion or undesired styling.

🧰 Tools
🪛 Biome (1.9.4)

[error] 15-15: Unexpected shorthand property background after background-image

(lint/suspicious/noShorthandPropertyOverrides)


[error] 15-15: Unexpected shorthand property text-decoration after text-decoration-thickness

(lint/suspicious/noShorthandPropertyOverrides)

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9fac744 and 2d7abf7.

📒 Files selected for processing (4)
  • wp-content/civi-extensions/goonjcustom/Civi/GoonjInitiatedEventsService.php (1 hunks)
  • wp-content/civi-extensions/goonjcustom/templates/CRM/Goonjcustom/Tabs/Events.tpl (1 hunks)
  • wp-content/themes/goonj-crm/assets/styles/goonj-main.scss (2 hunks)
  • wp-content/themes/goonj-crm/style.css (1 hunks)
🧰 Additional context used
🪛 Biome (1.9.4)
wp-content/themes/goonj-crm/style.css

[error] 15-15: Unexpected shorthand property background after background-image

(lint/suspicious/noShorthandPropertyOverrides)


[error] 15-15: Unexpected shorthand property text-decoration after text-decoration-thickness

(lint/suspicious/noShorthandPropertyOverrides)

🔇 Additional comments (3)
wp-content/civi-extensions/goonjcustom/templates/CRM/Goonjcustom/Tabs/Events.tpl (1)

1-5: Looks Good: AngularJS Integration for Events

This template snippet effectively integrates AngularJS components for event data. It dynamically passes the event ID to the directive, keeping the structure concise and readable.

wp-content/civi-extensions/goonjcustom/Civi/GoonjInitiatedEventsService.php (2)

21-26: Modular and Extensible Event Hook Subscriptions

The subscription to CiviCRM hooks for event QR generation and tab configuration is well-structured. This approach centralizes event-specific logic in one class, promoting single responsibility and maintainability.


78-79: Undefined variable $campId — Previously Flagged

This was noted in a prior review. The variable $campId does not exist in the current scope, but is referenced in the exception log string. Please replace it with $eventId or remove it if not needed.

Comment on lines +98 to +100
fieldset > div:nth-last-child(4) {
display: none !important;
}
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

Consolidate duplicate nth-last-child rules

The same rule for hiding the 4th-to-last child is duplicated in two places. This violates the DRY principle and makes maintenance harder.

Consider consolidating these rules using a shared selector or SCSS mixin:

// Define a mixin for hiding elements
@mixin hide-last-n-children($count) {
  > div:nth-last-child(-n+#{$count}) {
    display: none !important;
  }
}

// Use it in both places
.crm-public-form-item fieldset,
#crm-main-content-wrapper form .crm-block fieldset fieldset {
  @include hide-last-n-children(4);
}

Also applies to: 277-279

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: 9

🧹 Nitpick comments (4)
wp-content/civi-extensions/goonjcustom/Civi/GoonjInitiatedEventsService.php (1)

13-14: Consider splitting the service class based on responsibilities.

The class currently handles multiple unrelated responsibilities (email sending, QR code generation, and tab management), which violates the Single Responsibility Principle.

Consider splitting into separate services:

  • EventEmailService - Handle email-related operations
  • EventQRCodeService - Handle QR code generation
  • EventTabService - Handle tab management
wp-content/plugins/goonj-blocks/src/render.php (1)

235-235: Simplify target type checking.

The repeated use of in_array with a long list of targets could be simplified using a constant or configuration array.

+const VALID_TARGETS = [
+  'collection-camp',
+  'institution-collection-camp',
+  'dropping-center',
+  'goonj-activities',
+  'institution-dropping-center',
+  'institution-goonj-activities',
+  'events'
+];

-if (in_array($target, ['collection-camp','institution-collection-camp', 'dropping-center', 'goonj-activities', 'institution-dropping-center', 'institution-goonj-activities', 'events'])) :
+if (in_array($target, VALID_TARGETS)) :

Also applies to: 271-271

wp-content/plugins/goonj-blocks/build/render.php (2)

289-294: Consider consistent address formatting

The code uses different address formatting methods based on the target type. This inconsistency could lead to maintenance issues.

Consider using CRM_Utils_Address::format() consistently across all target types if it provides better formatting:

- if ($target === 'events') {
-     echo CRM_Utils_Address::format($address);
- } else {
-     echo esc_html($address);
- }
+ echo CRM_Utils_Address::format($address);

Alternatively, document why events require different address formatting.


235-235: Simplify target validation

The target validation uses a long in_array check with multiple values. This could be simplified using array operations.

Consider using a constant or configuration array:

+ const VALID_TARGETS = [
+     'collection-camp',
+     'institution-collection-camp',
+     'dropping-center',
+     'goonj-activities',
+     'institution-dropping-center',
+     'institution-goonj-activities',
+     'events'
+ ];

- if (in_array($target, ['collection-camp','institution-collection-camp', 'dropping-center', 'goonj-activities', 'institution-dropping-center', 'institution-goonj-activities', 'events'])) :
+ if (in_array($target, VALID_TARGETS)) :
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2d7abf7 and 07dfb98.

📒 Files selected for processing (4)
  • wp-content/civi-extensions/goonjcustom/Civi/GoonjInitiatedEventsService.php (1 hunks)
  • wp-content/civi-extensions/goonjcustom/templates/CRM/Goonjcustom/Tabs/Events.tpl (1 hunks)
  • wp-content/plugins/goonj-blocks/build/render.php (6 hunks)
  • wp-content/plugins/goonj-blocks/src/render.php (6 hunks)
🔇 Additional comments (2)
wp-content/civi-extensions/goonjcustom/Civi/GoonjInitiatedEventsService.php (1)

78-79: Fix variable naming inconsistency.

The error message uses $campId but the variable is named $eventId.

wp-content/plugins/goonj-blocks/build/render.php (1)

28-29: LGTM: Heading entry follows existing pattern

The addition of events-related headings maintains consistency with the existing code structure.

Comment on lines +1 to +4
<crm-angular-js modules="{$tabValue.module}">
<form id="bootstrap-theme">
<{$tabValue.directive} options="{ldelim}eventID: {$tabValue.entity.id}{rdelim}"></{$tabValue.directive}>
</form>
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue

Add CSRF protection to the form.

The form lacks CSRF protection which could make it vulnerable to cross-site request forgery attacks.

Add a CSRF token to the form:

 <form id="bootstrap-theme">
+  {crmKey name="crm-token"}
   <{$tabValue.directive} options="{ldelim}eventID: {$tabValue.entity.id}{rdelim}"></{$tabValue.directive}>
 </form>
📝 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
<crm-angular-js modules="{$tabValue.module}">
<form id="bootstrap-theme">
<{$tabValue.directive} options="{ldelim}eventID: {$tabValue.entity.id}{rdelim}"></{$tabValue.directive}>
</form>
<crm-angular-js modules="{$tabValue.module}">
<form id="bootstrap-theme">
{crmKey name="crm-token"}
<{$tabValue.directive} options="{ldelim}eventID: {$tabValue.entity.id}{rdelim}"></{$tabValue.directive}>
</form>

Comment on lines +5 to +8
<script>
console.log("Tab Value:", {$tabValue|json_encode|escape:'js'});
console.log("Event ID:", {$tabValue.entity.id|default:'undefined'});
</script>
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

Remove debug console.log statements.

Debug logging should not be present in production code as it could expose sensitive information.

-  <script>
-    console.log("Tab Value:", {$tabValue|json_encode|escape:'js'});
-    console.log("Event ID:", {$tabValue.entity.id|default:'undefined'});
-</script>

Comment on lines +169 to +200
// function goonjActivitiesTabset($tabsetName, &$tabs, $context) {
// // Check if the tabset is for Event Management
// if ($tabsetName == 'civicrm/event/manage') {
// // Ensure the event ID is available in the context
// if (!empty($context['event_id'])) {
// $eventID = $context['event_id'];
// \Civi::log()->info('eventID', ['eventID'=>$eventID]);

// // Construct the URL to the Search Kit view with the event ID filter in hash fragment
// $url = \CRM_Utils_System::url(
// 'civicrm/events-material-contributions'
// ) . "#?Material_Contribution.Event=$eventID";

// // Add the "Material Contributions" tab
// $newTab = [
// 'id' => 'material_contributions', // Unique identifier for the tab
// 'title' => ts('Material Contributions'),
// 'link' => $url, // URL to the Search Kit view
// 'valid' => true, // Ensures the tab is valid
// 'active' => true, // Activates the tab
// 'current' => false, // Indicates this tab is not the currently active tab
// ];

// // Insert the new tab into the tabs array (e.g., at position 4)
// $tabs = array_merge(
// array_slice($tabs, 0, 4), // Tabs before the new tab
// [$newTab], // The new tab
// array_slice($tabs, 4) // Tabs after the new tab
// );
// }
// }
// }
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

Remove commented-out code.

Large blocks of commented-out code make the file harder to maintain and understand. If this code is no longer needed, remove it. If it might be needed later, track it in version control.

Also applies to: 202-254

Comment on lines +45 to +49
$eventAttendedBy = Contact::get(FALSE)
->addSelect('email.email', 'display_name')
->addJoin('Email AS email', 'LEFT')
->addWhere('id', '=', $eventAttendedById)
->execute()->single();
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue

Add error handling for API calls.

The Contact API call lacks proper error handling. If the contact is not found, it will throw an exception that's not properly caught.

-        $eventAttendedBy = Contact::get(FALSE)
-          ->addSelect('email.email', 'display_name')
-          ->addJoin('Email AS email', 'LEFT')
-          ->addWhere('id', '=', $eventAttendedById)
-          ->execute()->single();
+        try {
+          $eventAttendedBy = Contact::get(FALSE)
+            ->addSelect('email.email', 'display_name')
+            ->addJoin('Email AS email', 'LEFT')
+            ->addWhere('id', '=', $eventAttendedById)
+            ->execute()->single();
+        } catch (\Exception $e) {
+          \Civi::log()->error('Failed to fetch contact details: ' . $e->getMessage());
+          throw new \Exception('Failed to fetch contact details');
+        }
📝 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
$eventAttendedBy = Contact::get(FALSE)
->addSelect('email.email', 'display_name')
->addJoin('Email AS email', 'LEFT')
->addWhere('id', '=', $eventAttendedById)
->execute()->single();
try {
$eventAttendedBy = Contact::get(FALSE)
->addSelect('email.email', 'display_name')
->addJoin('Email AS email', 'LEFT')
->addWhere('id', '=', $eventAttendedById)
->execute()->single();
} catch (\Exception $e) {
\Civi::log()->error('Failed to fetch contact details: ' . $e->getMessage());
throw new \Exception('Failed to fetch contact details');
}

Comment on lines +84 to +88
$event_material_contribution_link = sprintf(
'/events-contribution-verification/?source=%s&target_id=%s',
$action_target['title'],
$action_target['id'],
);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue

Sanitize URL parameters for event contribution link.

The URL parameters are not properly sanitized before being used in the link generation.

 $event_material_contribution_link = sprintf(
     '/events-contribution-verification/?source=%s&target_id=%s',
-    $action_target['title'],
-    $action_target['id'],
+    urlencode($action_target['title']),
+    urlencode($action_target['id']),
 );
📝 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
$event_material_contribution_link = sprintf(
'/events-contribution-verification/?source=%s&target_id=%s',
$action_target['title'],
$action_target['id'],
);
$event_material_contribution_link = sprintf(
'/events-contribution-verification/?source=%s&target_id=%s',
urlencode($action_target['title']),
urlencode($action_target['id']),
);

Comment on lines +224 to +232
'events' => [
'start_time' => 'start_date',
'end_time' => 'end_date',
'address' => 'address',
'address_label' => 'Address of the camp',
'contribution_link' => $event_material_contribution_link,
'donation_link' => $event_donation_link,
'register_link' => $institution_goonj_activities_register_link
]
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix incorrect register link in events configuration.

The events configuration is using $institution_goonj_activities_register_link instead of a dedicated events register link.

   'events' => [
     'start_time' => 'start_date',
     'end_time' => 'end_date',
     'address' => 'address',
     'address_label' => 'Address of the camp',
     'contribution_link' => $event_material_contribution_link,
     'donation_link' => $event_donation_link,
-    'register_link' => $institution_goonj_activities_register_link
+    'register_link' => sprintf(
+      '/volunteer-registration/form/#?source=%s&state_province_id=%s&city=%s',
+      urlencode($action_target['title']),
+      urlencode($action_target['state']),
+      urlencode($action_target['city'])
+    )
   ]

Committable suggestion skipped: line range outside the PR's diff.

Comment on lines +159 to +167
$eventSourceField = CustomField::get(FALSE)
->addSelect('id')
->addWhere('custom_group_id:name', '=', 'Contribution_Details')
->addWhere('name', '=', 'Events')
->execute()->single();
$eventSourceFieldId = 'custom_' . $eventSourceField['id'];
$base_event_donation_link = home_url('/contribute/donate');
$event_donation_link = $base_event_donation_link . '?' . $eventSourceFieldId . '=' . $source_contact_id;

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

Extract custom field retrieval logic

The custom field retrieval pattern is repeated three times in the code (for source, PU source, and event source fields). This violates the DRY principle.

Consider extracting this into a reusable function:

+ function get_custom_field_id($group_name, $field_name) {
+     $field = CustomField::get(FALSE)
+         ->addSelect('id')
+         ->addWhere('custom_group_id:name', '=', $group_name)
+         ->addWhere('name', '=', $field_name)
+         ->execute()
+         ->single();
+     return 'custom_' . $field['id'];
+ }

- $eventSourceField = CustomField::get(FALSE)
-   ->addSelect('id')
-   ->addWhere('custom_group_id:name', '=', 'Contribution_Details')
-   ->addWhere('name', '=', 'Events')
-   ->execute()->single();
- $eventSourceFieldId = 'custom_' . $eventSourceField['id'];
+ $eventSourceFieldId = get_custom_field_id('Contribution_Details', 'Events');
📝 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
$eventSourceField = CustomField::get(FALSE)
->addSelect('id')
->addWhere('custom_group_id:name', '=', 'Contribution_Details')
->addWhere('name', '=', 'Events')
->execute()->single();
$eventSourceFieldId = 'custom_' . $eventSourceField['id'];
$base_event_donation_link = home_url('/contribute/donate');
$event_donation_link = $base_event_donation_link . '?' . $eventSourceFieldId . '=' . $source_contact_id;
function get_custom_field_id($group_name, $field_name) {
$field = CustomField::get(FALSE)
->addSelect('id')
->addWhere('custom_group_id:name', '=', $group_name)
->addWhere('name', '=', $field_name)
->execute()
->single();
return 'custom_' . $field['id'];
}
$eventSourceFieldId = get_custom_field_id('Contribution_Details', 'Events');
$base_event_donation_link = home_url('/contribute/donate');
$event_donation_link = $base_event_donation_link . '?' . $eventSourceFieldId . '=' . $source_contact_id;

Comment on lines +224 to +232
'events' => [
'start_time' => 'start_date',
'end_time' => 'end_date',
'address' => 'address',
'address_label' => 'Address of the camp',
'contribution_link' => $event_material_contribution_link,
'donation_link' => $event_donation_link,
'register_link' => $institution_goonj_activities_register_link
]
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue

Verify the register_link assignment

The events target is using $institution_goonj_activities_register_link for its register_link. This seems incorrect as it's using an institution-specific link for a general event.

Consider creating a dedicated registration link for events:

'events' => [
    'start_time' => 'start_date',
    'end_time' => 'end_date',
    'address' => 'address',
    'address_label' => 'Address of the camp',
    'contribution_link' => $event_material_contribution_link,
    'donation_link' => $event_donation_link,
-    'register_link' => $institution_goonj_activities_register_link
+    'register_link' => sprintf(
+        '/volunteer-registration/form/#?source=%s&event_id=%s',
+        $action_target['title'],
+        $action_target['id']
+    )
]

Committable suggestion skipped: line range outside the PR's diff.

Comment on lines +84 to +89
$event_material_contribution_link = sprintf(
'/events-contribution-verification/?source=%s&target_id=%s',
$action_target['title'],
$action_target['id'],
);

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

Consider consolidating URL generation logic

The URL generation pattern is duplicated across multiple similar links (collection-camp, dropping-center, etc.). This violates the DRY principle.

Consider extracting the URL generation logic into a helper function:

+ function generate_contribution_link($type, $source, $target_id, $params = []) {
+     $base_url = sprintf('/%s-contribution/?source=%s&target_id=%s',
+         $type,
+         urlencode($source),
+         urlencode($target_id)
+     );
+     return add_query_args($base_url, $params);
+ }

- $event_material_contribution_link = sprintf(
-     '/events-contribution-verification/?source=%s&target_id=%s',
-     $action_target['title'],
-     $action_target['id'],
- );
+ $event_material_contribution_link = generate_contribution_link(
+     'events',
+     $action_target['title'],
+     $action_target['id']
+ );

Committable suggestion skipped: line range outside the PR's diff.

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: 1

🧹 Nitpick comments (4)
wp-content/civi-extensions/goonjcustom/Civi/CollectionCampService.php (4)

1249-1249: Reassess the clarity of this log message.
While logging isset($_GET[$sourceFieldId]) might help debugging, consider adding more descriptive text, so future maintainers better understand the context.


1253-1253: Avoid logging session key-values unless necessary.
Ensure that camp_source is not sensitive. Logging it can be helpful for debugging, but be sure it's safe to appear in logs.


1261-1261: Same caution: Consider logging policy.
“pu_source” is unlikely to be sensitive, but double-check any compliance requirements on logs.


1266-1272: Validate multiple GET parameter presence.
When more than one source parameter is passed, we always choose the first. Consider clarifying or handling conflicting sources more robustly if needed.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 07dfb98 and 9ebd412.

📒 Files selected for processing (2)
  • wp-content/civi-extensions/goonjcustom/Civi/CollectionCampService.php (3 hunks)
  • wp-content/civi-extensions/goonjcustom/Civi/GoonjInitiatedEventsService.php (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • wp-content/civi-extensions/goonjcustom/Civi/GoonjInitiatedEventsService.php
🔇 Additional comments (7)
wp-content/civi-extensions/goonjcustom/Civi/CollectionCampService.php (7)

1228-1228: Ensure sensitive or personal data is not logged.
Publicly logging user input might inadvertently expose sensitive information. Here it's likely benign, but carefully verify that only safe, non-sensitive data is being logged.


1256-1256: Session cleanup looks good.
Clearing other source keys maintains a single active source in the session. This chunk is conceptually correct.


1264-1265: Well-structured approach to ensuring a single source.
The code correctly unsets unneeded session keys, maintaining clarity of the active source.


1276-1276: Streamlined session clearing.
Unset all source-related session data if no parameter is found, preventing stale data from persisting.


1283-1283: Retrieving $eventSource from session looks fine.
This follows the same pattern as the other sources. Make sure it’s tested.


1295-1297: Extend existing logic to handle event source.
Good job integrating a new 'Events' source in the autoFill flow.


1302-1302: Initialize or unset all custom fields in a single block.
This code sets $autoFillData[$eventSourceFieldId] = NULL; to ensure a clean state; keep it consistent with other fields so no stale data remains.

Comment on lines +1239 to +1245
$eventSourceField = CustomField::get(FALSE)
->addSelect('id')
->addWhere('custom_group_id:name', '=', 'Contribution_Details')
->addWhere('name', '=', 'Events')
->execute()->single();
$eventSourceFieldId = 'custom_' . $eventSourceField['id'];

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue

Add null checks for $eventSourceField before using its properties.
If the 'Events' field doesn’t exist, $eventSourceField might be null, leading to a potential error when accessing $eventSourceField['id'].

+ if (!$eventSourceField) {
+   \Civi::log()->error("Unable to retrieve 'Events' custom field.");
+   return;
+ }
 $eventSourceFieldId = 'custom_' . $eventSourceField['id'];

Committable suggestion skipped: line range outside the PR's diff.

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: 5

♻️ Duplicate comments (1)
wp-content/civi-extensions/goonjcustom/Civi/GoonjInitiatedEventsService.php (1)

78-79: ⚠️ Potential issue

Use correct variable instead of $campId
The error message references $campId, which isn’t defined in this scope. This is similar to a previously flagged issue. Replace $campId with $eventId or remove it if not required.

- \Civi::log()->error("Error in sendLogisticsEmail for $campId " . $e->getMessage());
+ \Civi::log()->error("Error in sendLogisticsEmail for $eventId " . $e->getMessage());

Also applies to: 402-403

🧹 Nitpick comments (10)
wp-content/civi-extensions/goonjcustom/api/v3/Goonjcustom/GoonjInitiatedEventsFeedbackCron.php (1)

53-64: Add exception handling around email sending
Your code sends feedback emails and logs errors, which is good. Consider adding more targeted recovery steps if email sending fails (e.g., retries or a fallback).

wp-content/civi-extensions/goonjcustom/Civi/GoonjInitiatedEventsService.php (2)

91-98: Fix grammatical errors
The phrase “Their is one forms that require your attention” is grammatically incorrect. Use “There is one form that requires your attention” or “There are forms that require…” for clarity.

-    <p>Thank you for attending the goonj activity <strong>$eventId</strong>... Their is one forms that require ...
+    <p>Thank you for attending the goonj activity <strong>$eventId</strong>... There is one form that requires ...

Also applies to: 417-421


361-361: Unused $feedbackEmailSent variable
The variable $feedbackEmailSent is fetched but never used. If you intend to skip sending further emails based on this value, please add the necessary condition. Otherwise, remove it to reduce confusion.

wp-content/civi-extensions/goonjcustom/Civi/UrbanPlannedVisitService.php (1)

295-302: Consider clarifying method return type in the docblock.

Currently, the method sometimes returns FALSE, but the docblock doesn't indicate the possible return values. Updating it will help clarify what the callers might expect from this method.

wp-content/civi-extensions/goonjcustom/Civi/CollectionCampService.php (4)

1229-1229: Remove debug logging statements.

These debug logging statements should be removed before merging to production as they pollute the logs with unnecessary information.

-    \Civi::log()->info('sourceFieldId', ['sourceFieldId'=>$sourceFieldId]);
-    \Civi::log()->info('isset($_GET[$sourceFieldId]',['isset($_GET[$sourceFieldId]'=>isset($_GET[$sourceFieldId])]);
-    \Civi::log()->info('camp_source',['source'=>$_SESSION['camp_source']]);
-    \Civi::log()->info('pu_source',['pu_source'=>$_SESSION['pu_source']]);
-    \Civi::log()->info('eventSource',['eventSource'=>$_SESSION['eventSource']]);

Also applies to: 1250-1250, 1254-1254, 1262-1262, 1270-1270


1240-1246: Add null check for event source field.

Similar to the existing pattern for other source fields, add a null check before using the event source field to prevent potential errors.

 $eventSourceField = CustomField::get(FALSE)
   ->addSelect('id')
   ->addWhere('custom_group_id:name', '=', 'Contribution_Details')
   ->addWhere('name', '=', 'Events')
   ->execute()->single();
+if (!$eventSourceField) {
+  \Civi::log()->error("Unable to retrieve 'Events' custom field.");
+  return;
+}
 $eventSourceFieldId = 'custom_' . $eventSourceField['id'];

1535-1535: Replace magic number with a constant.

The payment instrument ID (4) should be defined as a class constant for better maintainability and readability.

+  const PAYMENT_INSTRUMENT_CHEQUE = 4;
+
   public function validateCheckNumber($formName, &$fields, &$files, &$form, &$errors) {
     if ($formName == 'CRM_Contribute_Form_Contribution') {
-      if (isset($fields['payment_instrument_id']) && $fields['payment_instrument_id'] == 4) {
+      if (isset($fields['payment_instrument_id']) && $fields['payment_instrument_id'] == self::PAYMENT_INSTRUMENT_CHEQUE) {

1542-1558: Move JavaScript code to a separate file.

The JavaScript code should be moved to a separate .js file and loaded using the proper asset management system. This improves maintainability and follows separation of concerns.

  1. Create a new file js/check-number-validation.js with the JavaScript code
  2. Load it using the CiviCRM resource management system:
-          \CRM_Core_Resources::singleton()->addScript("
-                    (function($) {
-                        function ensureErrorVisible() {
-                            var errorField = $('#check_number-error');
-                            var inputField = $('#check_number');
-                            $('.crm-error').hide();
-                            if (!errorField.length) {
-                                inputField.after('<div id=\"check_number-error\" class=\"crm-error\">' + " . json_encode($message) . " + '</div>');
-                            } else {
-                                errorField.show();
-                            }
-                        }
-
-                        $(document).ajaxComplete(ensureErrorVisible);
-                        $(document).ready(ensureErrorVisible);
-                    })(CRM.$);
-                ");
+          \CRM_Core_Resources::singleton()->addScriptFile('goonjcustom', 'js/check-number-validation.js');
+          \CRM_Core_Resources::singleton()->addVars('checkNumberValidation', [
+            'errorMessage' => $message
+          ]);
wp-content/civi-extensions/goonjcustom/Civi/InstitutionService.php (2)

47-49: DocBlock placeholders
These docblock lines do not provide new information. Consider adding relevant documentation or removing them to keep the code clean.


380-380: Simple null check
if ($contactId) { ... } is okay. Consider verifying the correct data type to avoid possible type juggling.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9ebd412 and 084834b.

📒 Files selected for processing (12)
  • wp-content/civi-extensions/civirazorpay/CRM/Core/Civirazorpay/Payment/Razorpay.php (2 hunks)
  • wp-content/civi-extensions/goonjcustom/Civi/CollectionCampService.php (5 hunks)
  • wp-content/civi-extensions/goonjcustom/Civi/GoonjInitiatedEventsService.php (1 hunks)
  • wp-content/civi-extensions/goonjcustom/Civi/InstitutionCollectionCampService.php (2 hunks)
  • wp-content/civi-extensions/goonjcustom/Civi/InstitutionDroppingCenterService.php (1 hunks)
  • wp-content/civi-extensions/goonjcustom/Civi/InstitutionGoonjActivitiesService.php (1 hunks)
  • wp-content/civi-extensions/goonjcustom/Civi/InstitutionService.php (5 hunks)
  • wp-content/civi-extensions/goonjcustom/Civi/UrbanPlannedVisitService.php (4 hunks)
  • wp-content/civi-extensions/goonjcustom/api/v3/Goonjcustom/GoonjInitiatedEventsCron.php (1 hunks)
  • wp-content/civi-extensions/goonjcustom/api/v3/Goonjcustom/GoonjInitiatedEventsFeedbackCron.php (1 hunks)
  • wp-content/civi-extensions/goonjcustom/api/v3/Goonjcustom/UrbanPlannedVisitOutcomeCron.php (1 hunks)
  • wp-content/civi-extensions/goonjcustom/templates/CRM/Contribute/Form/Contribution/ThankYou.tpl (0 hunks)
💤 Files with no reviewable changes (1)
  • wp-content/civi-extensions/goonjcustom/templates/CRM/Contribute/Form/Contribution/ThankYou.tpl
🚧 Files skipped from review as they are similar to previous changes (1)
  • wp-content/civi-extensions/goonjcustom/api/v3/Goonjcustom/GoonjInitiatedEventsCron.php
🔇 Additional comments (23)
wp-content/civi-extensions/goonjcustom/Civi/InstitutionDroppingCenterService.php (1)

102-102: Ensure usage of logical operators for boolean conditions
It appears the change from & to && resolves the logical requirement of checking that both $contactId and $groupId are truthy, rather than performing a bitwise operation. This is an appropriate fix that prevents potential misinterpretations in condition evaluation.

wp-content/civi-extensions/goonjcustom/api/v3/Goonjcustom/UrbanPlannedVisitOutcomeCron.php (1)

46-47: Check the logic around Outcome_Email_Sent conditions
These updated conditions ensure that rows are pulled if Outcome_Email_Sent is NULL or 0. Confirm that there's no overlap in how these states are used in your workflow (e.g., a default of NULL vs. 0).

wp-content/civi-extensions/goonjcustom/api/v3/Goonjcustom/GoonjInitiatedEventsFeedbackCron.php (1)

36-48: Validate participant status logic
The logic uses ->addWhere('participant.status_id', '=', 2) and an OR clause for Last_Reminder_Sent. Ensure that these status code references align with your participant statuses. Also confirm you want to limit the result to 25 records (->setLimit(25)), as this could miss remaining events.

wp-content/civi-extensions/civirazorpay/CRM/Core/Civirazorpay/Payment/Razorpay.php (2)

299-302: Subscription Cancelled event recognized
Excellent addition to handle subscription.cancelled. Verify that any upstream or downstream processes reliant on subscription status remain consistent.


449-498: Confirm user experience on forced cancellations
The processSubscriptionCancelled method sets the contribution status to “Cancelled” and updates the cancel_date. Confirm that end users (or staff) receive appropriate messaging about canceled subscriptions.

wp-content/civi-extensions/goonjcustom/Civi/UrbanPlannedVisitService.php (3)

6-7: Imports look good.

These new imports from Civi\Api4\Group and Civi\Api4\GroupContact are appropriate for the added group assignment feature.


304-314: Validate the existence of index keys in $individualData and $visitData.

In these lines, the code directly references ['id'], ['fields'], and ['Urban_Planned_Visit.State']. If these keys are missing or not expected, a PHP notice or error might be thrown. Consider adding checks or default values to handle these scenarios gracefully.


330-353: Check for a completely missing fallback group.

If no group is found during fallback, $stateContactGroup remains null, and this block attempts to log a non-existent 'title'. This will cause an error. Consider guarding against a null return, e.g., by logging a clearer warning and skipping group assignment if no fallback group can be found.

wp-content/civi-extensions/goonjcustom/Civi/InstitutionService.php (13)

5-5: No issues with newly added import statement
The addition of use Civi\Afform\Event\AfformSubmitEvent; looks appropriate and consistent with the file's requirements.


6-6: Imports look consistent
The new imports from Civi\Api4\* modules appear valid. Ensure that everything added is used within this file to keep the imports minimal and maintain clarity.


13-13: CoreUtil import is valid
Including use Civi\Api4\Utils\CoreUtil; is helpful for static method calls used later in the file.


24-24: Constant naming suggestion
Institution_INTENT_FB_NAME is readable and sufficiently descriptive as a constant. This change is acceptable.


26-26: Static field for address
Defining $instituteAddress as a static property is fine. Just ensure you reset it whenever needed if multiple submissions happen in a single request cycle.


33-36: Event subscriptions added with priority
Defining priorities [9, 8] is correct if the order is intentional. No further issues.


41-43: Renaming the hook pre function
Replacing 'assignChapterGroupToIndividual' with 'assignChapterGroupToContacts' clarifies that it can handle multiple contact types. Good approach.


50-82: Validating address capture logic
Overall, setInstituteAddress retrieves and stores state_province_id properly. However, be aware of edge cases (e.g., no address joined).


119-145: New approach for group assignment
assignChapterGroupToContacts unifies the logic for adding both Individual and Organization to the chapter group. This is a good improvement in design.


285-287: Chaining builder for Goonj_Office
The builder lines for updating Review.Goonj_Office are consistent. No additional concerns here.


322-322: Proper logical check
if ($coordinatorId && self::$organizationId) { is correct. Good usage of logical AND to ensure both IDs exist.


324-326: Chaining builder for Coordinating_POC
Similar to the Goonj_Office lines, these lines update a related field in an organized manner. No issues found.


382-384: Querying Type_of_Institution
Fetching Institute_Registration.Type_of_Institution:label is correct. Make sure you verify the expected structure if the label is missing.

wp-content/civi-extensions/goonjcustom/Civi/InstitutionCollectionCampService.php (2)

146-146: Assign chapter group condition
if ($objectName !== 'Eck_Collection_Camp' || !self::isCurrentSubtype($objectRef)) { return; } properly short-circuits. Ensure you handle all subtypes as needed or log the skip reason.


171-171: Logical AND check
if($contactId && $groupId){ ... } is correct to avoid attempts at creating group contact with invalid IDs. Good usage of try-catch for error handling.

*/
private static function addContactToGroup($contactId, $groupId) {
if($contactId & $groupID){
if($contactId & $groupId){
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue

Use logical AND (&&) instead of bitwise operator (&).

Here, the bitwise & operator can cause unexpected behavior if either value exceeds 1 in binary representation. The proper operator for checking the truthiness of both $contactId and $groupId is &&.

Apply this diff to fix the conditional check:

-    if($contactId & $groupId){
+    if ($contactId && $groupId) {
📝 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($contactId & $groupId){
if ($contactId && $groupId) {

Comment on lines +83 to +103
/**
*
*/
private static function getLogisticsEmailHtml($attendeeName, $eventId, $eventAttendedById, $eventCode, $eventAddress) {
$homeUrl = \CRM_Utils_System::baseCMSURL();
// Construct the full URLs for the forms.
$campOutcomeFormUrl = $homeUrl . 'goonj-initiated-events-outcome/#?Event1=' . $eventId . '&Goonj_Events_Outcome.Filled_By=' . $campAttendedById;

$html = "
<p>Dear $attendeeName,</p>
<p>Thank you for attending the goonj activity <strong>$eventId</strong> at <strong>$eventAddress</strong>. Their is one forms that require your attention during and after the goonj activity:</p>
<ol>
Please complete this form from the goonj activity location once the goonj activity ends.</li>
<li><a href=\"$campOutcomeFormUrl\">Goonj Activity Outcome Form</a><br>
This feedback form should be filled out after the goonj activity/session ends, once you have an overview of the event's outcomes.</li>
</ol>
<p>We appreciate your cooperation.</p>
<p>Warm Regards,<br>Urban Relations Team</p>";

return $html;
}
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

Hard-coded text could be externalized or templated
Your HTML strings are embedded directly in the method, making them harder to maintain. Consider external templates or translation functions for cleaner code and to support multi-language expansions.

Also applies to: 410-427

Comment on lines +318 to +324
if ($groupId & $contactId) {
GroupContact::create(FALSE)
->addValue('contact_id', $contactId)
->addValue('group_id', $groupId)
->addValue('status', 'Added')
->execute();
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue

Replace bitwise AND with a logical AND.

if ($groupId & $contactId) {
    // ...
}

This uses the bitwise AND operator (&) instead of the logical AND (&&). For boolean checks, you should use &&. Using & can lead to unintended behavior if $groupId or $contactId are numeric or not strictly boolean.

-if ($groupId & $contactId) {
+if ($groupId && $contactId) {
     GroupContact::create(FALSE)
       ->addValue('contact_id', $contactId)
       ->addValue('group_id', $groupId)
       ->addValue('status', 'Added')
       ->execute();
 }

$stateOfficeId = $stateOffice['id'];

if($stateOfficeId & self::$organizationId){
if ($stateOfficeId & self::$organizationId) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue

Replace bitwise operator with logical operator
Line 283 uses bitwise & instead of logical &&. This may lead to unexpected results.

-if ($stateOfficeId & self::$organizationId) {
+if ($stateOfficeId && self::$organizationId) {
📝 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 ($stateOfficeId & self::$organizationId) {
if ($stateOfficeId && self::$organizationId) {

Comment on lines +83 to +117
/**
*
*/
public static function setInstitutionPocAddress(AfformSubmitEvent $event) {
$afform = $event->getAfform();
$formName = $afform['name'];

if ($formName !== self::Institution_INTENT_FB_NAME) {
return;
}

$entityType = $event->getEntityType();

if (!CoreUtil::isContact($entityType)) {
return;
}

foreach ($event->records as $index => $contact) {
if (empty($contact['fields'])) {
continue;
}

$contactId = $contact['fields']['id'];

$stateProvinceId = self::$instituteAddress['state_province_id'];

$updateResults = Address::update(FALSE)
->addValue('state_province_id', $stateProvinceId)
->addWhere('contact_id', '=', $test)
->execute();
}

\Civi::log()->info('Address update results', $updateResults);

}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue

Potential bug with undeclared $test variable
In setInstitutionPocAddress(), line 111 uses ->addWhere('contact_id', '=', $test), but $test is never defined. This appears to be an accidental leftover that will cause runtime errors.

Suggested fix:

-    ->addWhere('contact_id', '=', $test)
+    ->addWhere('contact_id', '=', $contactId)
📝 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
/**
*
*/
public static function setInstitutionPocAddress(AfformSubmitEvent $event) {
$afform = $event->getAfform();
$formName = $afform['name'];
if ($formName !== self::Institution_INTENT_FB_NAME) {
return;
}
$entityType = $event->getEntityType();
if (!CoreUtil::isContact($entityType)) {
return;
}
foreach ($event->records as $index => $contact) {
if (empty($contact['fields'])) {
continue;
}
$contactId = $contact['fields']['id'];
$stateProvinceId = self::$instituteAddress['state_province_id'];
$updateResults = Address::update(FALSE)
->addValue('state_province_id', $stateProvinceId)
->addWhere('contact_id', '=', $test)
->execute();
}
\Civi::log()->info('Address update results', $updateResults);
}
/**
*
*/
public static function setInstitutionPocAddress(AfformSubmitEvent $event) {
$afform = $event->getAfform();
$formName = $afform['name'];
if ($formName !== self::Institution_INTENT_FB_NAME) {
return;
}
$entityType = $event->getEntityType();
if (!CoreUtil::isContact($entityType)) {
return;
}
foreach ($event->records as $index => $contact) {
if (empty($contact['fields'])) {
continue;
}
$contactId = $contact['fields']['id'];
$stateProvinceId = self::$instituteAddress['state_province_id'];
$updateResults = Address::update(FALSE)
->addValue('state_province_id', $stateProvinceId)
->addWhere('contact_id', '=', $contactId)
->execute();
}
\Civi::log()->info('Address update results', $updateResults);
}

@pokhiii pokhiii deleted the feat/goonj-initiated-events branch April 19, 2025 11:29
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.

4 participants