Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Better Form Stats #567

Merged
merged 11 commits into from
Sep 18, 2024
Merged

Better Form Stats #567

merged 11 commits into from
Sep 18, 2024

Conversation

chiragchhatrala
Copy link
Collaborator

@chiragchhatrala chiragchhatrala commented Sep 12, 2024

Summary by CodeRabbit

Release Notes

  • New Features

    • Introduced a new validation for date ranges in form statistics retrieval.
    • Added detailed statistics reporting for forms, including views, submissions, completion rates, and average submission duration.
    • Introduced a timer component to track form completion time, enhancing data collection for analytics.
  • Bug Fixes

    • Improved error messaging for missing or excessive date range parameters.
  • Tests

    • Added tests to verify the functionality of new form statistics features, including detailed checks for response data structure and values.

Copy link
Contributor

coderabbitai bot commented Sep 12, 2024

Warning

Rate limit exceeded

@JhumanJ has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 24 minutes and 10 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

Files that changed from the base of the PR and between 7ebf583 and 8c48776.

Walkthrough

The pull request enhances the handling of form statistics by implementing validation for date ranges and introducing a new method for detailed statistics in the backend. A new request class ensures structured validation, while the frontend introduces a timer component to track form completion times, providing valuable analytics data.

Changes

File Path Change Summary
api/app/Http/Controllers/Forms/FormStatsController.php Added validation for date range and new method getFormStatsDetails for detailed statistics.
api/app/Http/Requests/FormStatsRequest.php Introduced FormStatsRequest for structured validation of date parameters with custom logic.
api/tests/Feature/Forms/FormStatTest.php Introduced tests for verifying form statistics details and modified existing tests for date parameters.
client/components/open/forms/OpenCompleteForm.vue Introduced FormTimer component to track completion time of forms and manage timer lifecycle.
client/components/open/forms/FormTimer.vue New FormTimer component that implements timer functionality for tracking form completion time.

Possibly related PRs

  • Form analytics now paid feature #547: The changes in FormStatsController.php regarding the handling of form statistics and the introduction of a new method for detailed statistics are directly related to the enhancements made in the main PR, which also focuses on improving the functionality of form statistics.

🐰 "In fields of forms, we hop and play,
With timers and stats to brighten the day.
Completion times, we now can see,
A joyful leap in analytics, whee!
So gather your data, let it unfold,
In our rabbit world, new stories are told!" 🐇✨


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 generate interesting stats about this repository and render them as a table.
    -- @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.

Copy link
Contributor

@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

Outside diff range and nitpick comments (2)
client/components/open/forms/FormTimer.vue (1)

1-57: Consider minor refactorings to improve code readability and simplify the logic.

Here are a few suggestions to improve the code:

  1. Extract the setInterval callback into a separate function for better readability.
  2. Simplify the completionTime watcher by directly calling pendingSubmission.setTimer.
  3. Update the resetTimer method to directly set completionTime.value to null instead of relying on the watcher.

Apply this diff to implement the suggested refactorings:

-watch(() => completionTime.value, () => {
-  if (completionTime.value) {
-    pendingSubmission.setTimer(completionTime.value)
-  }
-}, { immediate: true })
+watch(() => completionTime.value, (newValue) => {
+  pendingSubmission.setTimer(newValue)
+}, { immediate: true })

+const incrementCompletionTime = () => {
+  completionTime.value += 1
+}
+
 const startTimer = () => {
   if (!startTime.value) {
     startTime.value = parseInt(pendingSubmission.getTimer() ?? 1)
     completionTime.value = startTime.value
-    timer = setInterval(() => {
-      completionTime.value += 1
-    }, 1000)
+    timer = setInterval(incrementCompletionTime, 1000)
   }
 }
 
 const resetTimer = () => {
   stopTimer()
   startTime.value = null
-  completionTime.value = null
+  completionTime.value = null
 }
client/pages/forms/[slug]/show/stats.vue (1)

3-169: The new card layout for displaying form analytics looks great!

The consistent structure of the cards with loading indicators, actual values for pro users, and blurred placeholders for non-pro users provides a clear and user-friendly presentation of the analytics data.

I noticed a commented-out section (lines 94-169) with a similar card layout using the UCard component. Is this an alternative implementation that you were considering? If it's no longer needed, consider removing it to keep the codebase clean.

Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

Commits

Files that changed from the base of the PR and between 2c70ed0 and 4f1befa.

Files selected for processing (13)
  • api/app/Http/Controllers/Forms/FormStatsController.php (3 hunks)
  • api/app/Http/Controllers/Forms/PublicFormController.php (2 hunks)
  • api/app/Http/Resources/FormSubmissionResource.php (1 hunks)
  • api/app/Jobs/Form/StoreFormSubmissionJob.php (2 hunks)
  • api/app/Models/Forms/FormSubmission.php (1 hunks)
  • api/database/migrations/2024_09_09_180618_add_completion_time_to_form_submissions.php (1 hunks)
  • api/routes/api.php (1 hunks)
  • api/tests/Feature/Forms/FormStatTest.php (1 hunks)
  • client/components/open/forms/FormTimer.vue (1 hunks)
  • client/components/open/forms/OpenCompleteForm.vue (7 hunks)
  • client/components/open/forms/components/FormStats.vue (5 hunks)
  • client/composables/forms/pendingSubmission.js (2 hunks)
  • client/pages/forms/[slug]/show/stats.vue (2 hunks)
Additional comments not posted (33)
api/app/Models/Forms/FormSubmission.php (2)

14-14: LGTM!

Adding completion_time to the $fillable array is a good change. It allows the attribute to be mass assignable, which is useful for creating or updating records using arrays. The attribute name is clear and follows the naming convention.


21-21: Ensure type consistency when setting the attribute.

Casting completion_time to an integer in the model is a good practice. It ensures that the attribute will always be an integer when accessing it from the model instance.

Please verify that completion_time is being set with an integer value in other parts of the codebase where this model is being used (e.g., controllers, services, tests). This is to ensure type consistency and avoid unexpected behavior.

Run the following script to verify the attribute usage:

api/database/migrations/2024_09_09_180618_add_completion_time_to_form_submissions.php (1)

1-27: LGTM!

The migration file is well-structured and follows Laravel's conventions. The completion_time column is appropriately defined as an integer type and marked as nullable. The up and down methods correctly handle adding and removing the column, respectively.

client/components/open/forms/FormTimer.vue (1)

1-57: LGTM! The component implementation looks good.

The component follows Vue 3 Composition API best practices and correctly handles the timer lifecycle based on user interactions and component lifecycle hooks. The use of pendingSubmission composable for state management is a good approach. The component exposes the necessary methods and state to be used by the parent component.

client/composables/forms/pendingSubmission.js (4)

10-12: LGTM!

The computed property formPendingSubmissionTimerKey is correctly implemented. It derives a unique key for storing the timer associated with the pending submission by suffixing the existing formPendingSubmissionKey with "-timer".


34-37: LGTM!

The setTimer function is correctly implemented. It allows for setting a timer value in storage and includes a check for server-side execution to ensure that timer management only occurs in client-side contexts.


39-41: LGTM!

The removeTimer function is correctly implemented. It provides a convenient way to clear the timer by setting it to null using the setTimer function.


43-46: LGTM!

The getTimer function is correctly implemented. It retrieves the current timer value from storage, providing a default value if none exists. It also includes a check for server-side execution to ensure that timer retrieval only occurs in client-side contexts.

api/app/Http/Resources/FormSubmissionResource.php (1)

26-27: LGTM!

The addition of the completion_time field enhances the data structure by providing more detailed information in the response. The logic for conditionally including form_id and id remains unchanged, preserving the overall control flow of the method. The changes are consistent with the AI-generated summary.

api/app/Http/Controllers/Forms/FormStatsController.php (3)

23-28: LGTM!

The validation logic for checking the date range is correctly implemented. The error message is clear and provides actionable information to the user.


Line range hint 32-42: LGTM!

The logic for retrieving form statistics for the specified date range is correctly implemented. The function correctly handles the case when the current date is included in the date range.


47-64: LGTM!

The new getFormStatsDetails function is correctly implemented and provides useful statistics about the form. The function correctly handles the case when there are no submissions with a completion time recorded. The average duration is formatted appropriately for human readability using Carbon's interval formatting.

api/tests/Feature/Forms/FormStatTest.php (2)

Line range hint 5-67: LGTM!

The test case is correctly verifying the chart data by creating form views and submissions for past days and current day, running the database cleanup command, and checking the API response contains the expected chart data.


70-101: LGTM!

The test case is correctly verifying the stats details by creating form submissions with varying completion times, including incomplete submissions, to test the average duration and completion rate calculations, creating a set number of form views to test the views count, and checking the API response contains the expected stats details.

api/app/Http/Controllers/Forms/PublicFormController.php (3)

80-81: LGTM!

The formatting change improves code consistency without affecting the functionality.


92-94: LGTM!

The changes improve the structure and clarity of the code by:

  • Storing the validated data in a separate variable $submissionData.
  • Extracting the completion_time field into a separate variable $completionTime.
  • Unsetting the completion_time field from the $submissionData array.

This allows for better management of the completion_time field and ensures that it is treated separately when creating a new instance of StoreFormSubmissionJob.


97-97: LGTM!

The StoreFormSubmissionJob is correctly instantiated with the modified parameters, including the new $completionTime variable. This is consistent with the extraction of completion_time into a separate variable and ensures that it is passed along with the form and submission data to the job.

Also applies to: 101-101

client/components/open/forms/components/FormStats.vue (5)

2-15: LGTM!

The code segment is well-structured and uses the DateInput component correctly. The disabled prop is set based on the form.is_pro value, ensuring that only professional users can filter the analytics by date range.


17-46: LGTM!

The code segment is well-structured and uses conditional rendering correctly based on the form.is_pro value. The pro-tag and v-button components are used appropriately for displaying the subscription prompt.


48-56: LGTM!

The code segment uses conditional rendering correctly to display the loading indicator or the line chart based on the isLoading value and the form.is_pro value. The Loader and LineChart components are used appropriately.


Line range hint 86-100: LGTM!

The code segment uses the composition API correctly. The filterForm is defined using the useForm function, and the filter_date field is initialized appropriately. The subscriptionModalStore and filterForm are returned correctly from the setup function.


Line range hint 137-181: LGTM!

The code segment uses the options API correctly. The watcher on the filterForm is defined correctly and triggers data fetching when a valid date range is selected. The initialization of the date range for professional users in the mounted hook is appropriate. The update to the getChartData method to include date parameters in the API request is correct. The error handling for the API call is implemented correctly using the catch block and displaying an error alert using the useAlert function.

client/pages/forms/[slug]/show/stats.vue (1)

189-216: The script section looks good!

The reactive variables and the getCardData function provide a clean and modular way to fetch and store the analytics data. Calling getCardData in the onMounted hook ensures that the data is fetched when the component is mounted, and the fetched data is properly assigned to the respective reactive variables.

I like how you've checked if the form is valid and if the user has pro access before making the API call in the getCardData function. This is a good practice to prevent unnecessary API calls and handle access control.

api/app/Jobs/Form/StoreFormSubmissionJob.php (3)

36-36: LGTM!

The addition of the optional $completionTime parameter to the constructor is a clean and non-breaking change. The type declaration ?int allows for flexibility in usage, and the default value of null ensures backward compatibility. Good job!


73-73: Looks good!

The update to the completion_time field of the $previousSubmission when updating an existing submission is consistent with the new functionality introduced by the $completionTime parameter. This ensures that the completion time is properly recorded for updated submissions.


79-79: Looks good!

Setting the completion_time field when creating a new submission is consistent with the new functionality introduced by the $completionTime parameter. This ensures that the completion time is properly recorded for new submissions.

client/components/open/forms/OpenCompleteForm.vue (6)

7-10: LGTM!

The addition of the FormTimer component and passing the form prop to it looks good. This aligns with the PR objective of tracking form completion time.


208-208: LGTM!

The import statement for the FormTimer component is correct.


217-217: LGTM!

The FormTimer component is correctly registered in the components option.


283-288: LGTM!

The timer is correctly stopped, and the completion time is retrieved and assigned to the form data before submitting the form.


303-304: LGTM!

The completion_time is correctly included in the submission_data payload.


312-312: LGTM!

The timer is correctly:

  • Removed after a successful form submission.
  • Reset when the form submission fails.
  • Reset when the form is restarted.

This ensures that the timer is properly managed in different scenarios.

Also applies to: 332-332, 343-343

api/routes/api.php (1)

149-149: LGTM!

The new route for retrieving detailed form statistics is well-defined and follows the existing conventions. It is correctly placed within the 'pro-form' middleware group to restrict access to users with a pro subscription. The route URL and name are consistent with the other form-related routes.

Copy link
Contributor

@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

Outside diff range and nitpick comments (1)
api/app/Http/Controllers/Forms/FormStatsController.php (1)

53-70: Consider utilizing the date range from the request.

For consistency with the getFormStats method, consider utilizing the date range from the request when calculating the statistics in this method. This would ensure that the statistics returned by both methods are based on the same date range.

Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

Commits

Files that changed from the base of the PR and between e6bcdd5 and 4bc1fb7.

Files selected for processing (1)
  • api/app/Http/Controllers/Forms/FormStatsController.php (3 hunks)
Additional comments not posted (3)
api/app/Http/Controllers/Forms/FormStatsController.php (3)

23-35: LGTM!

The validation checks for the date range are correctly implemented and provide appropriate error messages to guide the user. The logic for restricting the date range to a maximum of 3 months is also correct.


Line range hint 36-50: LGTM!

The logic for retrieving form statistics based on the user-defined date range is correct. The use of CarbonPeriod to iterate over the date range is an efficient approach. The method is also correctly handling the case when the current date is included in the date range by adding the current day's views to the statistics.


53-70: LGTM!

The method is correctly calculating the total views, total submissions, completion rate, and average submission duration. The use of Carbon's interval formatting to make the average duration human-readable is a nice touch. The completion rate calculation is also correctly handling the case when there are no views to avoid division by zero.

@JhumanJ JhumanJ merged commit ceb0648 into main Sep 18, 2024
5 checks passed
@JhumanJ JhumanJ deleted the 6851e-better-stats branch September 18, 2024 17:20
@coderabbitai coderabbitai bot mentioned this pull request Feb 20, 2025
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