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

Add contact support #94

Merged
merged 2 commits into from
Jan 10, 2025
Merged

Add contact support #94

merged 2 commits into from
Jan 10, 2025

Conversation

cp-amisha-i
Copy link
Collaborator

@cp-amisha-i cp-amisha-i commented Jan 3, 2025

Simulator.Screen.Recording.-.iPhone.16.-.2025-01-06.at.19.21.26.1.mp4

Simulator Screenshot - iPad mini (A17 Pro) - 2025-01-08 at 16 06 50 (1)

Summary by CodeRabbit

Release Notes

  • New Features

    • Added Feedback functionality to the app.
    • Introduced multi-media selection for attachments.
    • Enhanced device and app version information capture.
    • New feedback repository and store for managing feedback data.
  • Improvements

    • Replaced email contact method with in-app feedback submission.
    • Updated media picker options across various views.
    • Improved attachment handling and storage management.
    • Added new color options for UI elements.
    • Streamlined user interface for feedback collection.
  • Bug Fixes

    • Refined image and attachment upload processes.
    • Enhanced error handling for media selections.
  • Chores

    • Updated project configurations and localization strings.
    • Implemented backend services for feedback processing.
    • Adjusted Firestore rules for new feedback collection.

These release notes provide a concise overview of the significant changes in the application, focusing on user-facing improvements and new functionalities.

Copy link

coderabbitai bot commented Jan 3, 2025

Warning

Rate limit exceeded

@cp-amisha-i has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 26 minutes and 5 seconds before requesting another review.

⌛ How to resolve this issue?

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

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

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

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

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between 21f75ec and e71d5ec.

⛔ Files ignored due to path filters (2)
  • firebase-debug.log is excluded by !**/*.log
  • functions/firestore-debug.log is excluded by !**/*.log
📒 Files selected for processing (42)
  • BaseStyle/BaseStyle.xcodeproj/project.pbxproj (4 hunks)
  • BaseStyle/BaseStyle/CustomUI/Buttons/DismissButton.swift (2 hunks)
  • BaseStyle/BaseStyle/CustomUI/MailComposeView.swift (0 hunks)
  • BaseStyle/BaseStyle/CustomUI/MediaPickerOptionsView.swift (1 hunks)
  • BaseStyle/BaseStyle/CustomUI/MultiMediaSelectionPickerView.swift (1 hunks)
  • BaseStyle/BaseStyle/Extension/UIImage+Extension.swift (1 hunks)
  • BaseStyle/BaseStyle/Resource/AppColors.swift (1 hunks)
  • BaseStyle/BaseStyle/Resource/BaseAssets.xcassets/Colors/ErrorColor.colorset/Contents.json (1 hunks)
  • BaseStyle/BaseStyle/Resource/BaseAssets.xcassets/Colors/SecondaryLightTextColor.colorset/Contents.json (1 hunks)
  • Data/Data.xcodeproj/project.pbxproj (9 hunks)
  • Data/Data/DI/AppAssembly.swift (2 hunks)
  • Data/Data/Helper/Firebase/StorageManager.swift (2 hunks)
  • Data/Data/Model/Feedback.swift (1 hunks)
  • Data/Data/Repository/ExpenseRepository.swift (2 hunks)
  • Data/Data/Repository/FeedbackRepository.swift (1 hunks)
  • Data/Data/Repository/GroupRepository.swift (2 hunks)
  • Data/Data/Repository/TransactionRepository.swift (2 hunks)
  • Data/Data/Repository/UserRepository.swift (2 hunks)
  • Data/Data/Router/AppRoute.swift (2 hunks)
  • Data/Data/Store/FeedbackStore.swift (1 hunks)
  • Data/Data/Utils/DeviceInfo.swift (1 hunks)
  • Splito.xcodeproj/project.pbxproj (5 hunks)
  • Splito/Localization/Localizable.xcstrings (7 hunks)
  • Splito/UI/Home/Account/AccountHomeView.swift (2 hunks)
  • Splito/UI/Home/Account/AccountHomeViewModel.swift (2 hunks)
  • Splito/UI/Home/Account/AccountRouteView.swift (1 hunks)
  • Splito/UI/Home/Account/Feedback/FeedbackView.swift (1 hunks)
  • Splito/UI/Home/Account/Feedback/FeedbackViewModel.swift (1 hunks)
  • Splito/UI/Home/Account/User Profile/UserProfileView.swift (1 hunks)
  • Splito/UI/Home/Account/User Profile/UserProfileViewModel.swift (1 hunks)
  • Splito/UI/Home/ActivityLog/ActivityLogView.swift (1 hunks)
  • Splito/UI/Home/Expense/AddExpenseView.swift (1 hunks)
  • Splito/UI/Home/Expense/AddExpenseViewModel.swift (1 hunks)
  • Splito/UI/Home/Groups/Create Group/CreateGroupView.swift (1 hunks)
  • Splito/UI/Home/Groups/Create Group/CreateGroupViewModel.swift (1 hunks)
  • Splito/UI/Home/Groups/Group/Group Options/Settle up/Payment/GroupPaymentViewModel.swift (1 hunks)
  • firestore.rules (3 hunks)
  • functions/.gitignore (1 hunks)
  • functions/package.json (1 hunks)
  • functions/src/feedback/feedback_service.ts (1 hunks)
  • functions/src/index.ts (2 hunks)
  • functions/src/mail/mail_service.ts (1 hunks)

Walkthrough

This pull request introduces a comprehensive feedback system for the Splito application. The changes span multiple modules, including BaseStyle, Data, and Splito, and involve creating new components for feedback submission, attachment handling, and backend processing. The implementation includes new UI elements for submitting feedback, view models to manage the feedback process, repository and store classes for data management, and cloud functions to handle feedback creation and email notifications. Additionally, several existing components were modified to integrate with the new feedback system.

Changes

Module Files Change Summary
BaseStyle CustomUI/MediaPickerOptionsView.swift, Extension/UIImage+Extension.swift, CustomUI/MultiMediaSelectionPickerView.swift, CustomUI/MailComposeView.swift Added media picker and image extension utilities; removed mail compose view
Data Repository/FeedbackRepository.swift, Repository/ExpenseRepository.swift, Repository/GroupRepository.swift, Repository/TransactionRepository.swift, Repository/UserRepository.swift, Store/FeedbackStore.swift, Model/Feedback.swift, Router/AppRoute.swift, DI/AppAssembly.swift, Helper/Firebase/StorageManager.swift, Utils/DeviceInfo.swift Added feedback-related classes and repositories; modified existing repositories for attachment handling
Splito UI/Home/Account/Feedback/FeedbackView.swift, UI/Home/Account/Feedback/FeedbackViewModel.swift, UI/Home/Account/AccountHomeView.swift, UI/Home/Account/UserProfileView.swift, UI/Home/Expense/AddExpenseView.swift, UI/Home/Groups/CreateGroupView.swift, UI/Home/Groups/CreateGroupViewModel.swift, UI/Home/Groups/GroupOptions/SettleUp/Payment/GroupPaymentViewModel.swift, UI/Home/ActivityLog/ActivityLogView.swift Implemented feedback view, view model, and related components; updated routing and UI elements
Functions index.ts, feedback_service.ts, mail_service.ts Added cloud functions for feedback processing and email notifications; integrated AWS SES for email delivery
Localization Localizable.xcstrings Updated localization strings related to feedback functionality

Sequence Diagram

sequenceDiagram
    participant User
    participant FeedbackView
    participant FeedbackViewModel
    participant FeedbackRepository
    participant StorageManager
    participant CloudFunction

    User->>FeedbackView: Submit Feedback
    FeedbackView->>FeedbackViewModel: Validate Input
    FeedbackViewModel->>FeedbackRepository: Add Feedback
    FeedbackRepository->>StorageManager: Upload Attachments
    StorageManager-->>FeedbackRepository: Attachment URLs
    FeedbackRepository->>CloudFunction: Trigger Feedback Created Event
    CloudFunction->>MailService: Send Support Email
Loading

Poem

🐰 A Rabbit's Ode to Feedback Flow 🐰

With buttons bright and attachments clear,
Our feedback path is now sincere.
From user's tap to support's embrace,
A digital message finds its place.
CodeRabbit's magic, smooth and light! 🚀


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

@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: 6

🧹 Nitpick comments (22)
Splito/UI/Home/Account/User Profile/UserProfileViewModel.swift (1)

110-110: Consider adding or clarifying the logic for .removeAll

Currently, the .removeAll case is a no-op. If the planned functionality is to remove all user attachments or profile data, it would be helpful to either implement that logic or add a clear TODO comment explaining its future purpose. If there is no immediate plan to implement it, removing the unused case could keep the codebase concise.

 case .removeAll:
-    break
+    // TODO: Implement functionality to remove all user images or relevant attachments
Splito/UI/Home/ActivityLog/ActivityLogView.swift (1)

40-40: Consider localizing or dynamically configuring the new title text.

While replacing Text("Activity") with NavigationTitleTextView(text: "Activity"), ensure the text string is localized or dynamically updated if your app supports different languages or context-based titles. This helps maintain consistency with other localized text resources in the application.

Splito/UI/Home/Groups/Create Group/CreateGroupViewModel.swift (1)

81-81: Consider implementing logic for the new .removeAll action.

Currently, the .removeAll case is a no-op. If the purpose of this action is to remove/reset all images or other relevant data from the view model, you may want to add the appropriate logic here for consistency with the .remove case.

Would you like me to propose a revised implementation that clears all selected media?

Data/Data/Store/FeedbackStore.swift (1)

20-27: Use a consistent error log prefix.
The error logging refers to "ShareCodeStore" instead of "FeedbackStore" in its message. This may cause confusion during debugging.

- LogE("ShareCodeStore: \(#function) Failed to add shared code: \(error).")
+ LogE("FeedbackStore: \(#function) Failed to add feedback: \(error).")
Data/Data/Repository/FeedbackRepository.swift (1)

20-22: Check for large attachments.
Uploading large attachments can lead to timeouts or memory spikes. Consider adding validations or chunked uploads for reliability.

Splito/UI/Home/Account/AccountRouteView.swift (1)

24-25: Expose or document the FeedbackView navigation path.
Providing an explicit route to feedback is a great addition. Consider adding minimal inline documentation or usage examples to ensure the route is more discoverable by other developers.

BaseStyle/BaseStyle/Extension/UIImage+Extension.swift (1)

10-14: Consider allowing configurable compression quality for wider use cases.
Currently, the compression quality is hardcoded to 1.0. This might lead to large file sizes. Permit the caller to specify a custom compression factor for more flexibility.

BaseStyle/BaseStyle/CustomUI/MediaPickerOptionsView.swift (3)

10-24: Validate SwiftUI accessibility.
Ensure appropriate accessibility labels or modifiers are used for the MediaPickerOptionsView, particularly for any visual-only content like images, so that the view is accessible to screen readers.


26-43: Consider a more flexible layout approach.
In the body property, the logic toggles button visibility based on withRemoveAllOption. It might be beneficial to restructure the layout using SwiftUI stacks and conditionals to reduce branching and improve maintainability.


45-51: Enum naming clarity.
ActionsOfSheet might not be immediately recognizable across the wider codebase. A more descriptive name like MediaPickerAction or MediaPickerSheetAction may avoid confusion.

Data/Data/Model/Feedback.swift (1)

10-46: Validate required fields and ensure proper data integrity.
Currently, title, description, userId, appVersion, etc., are stored without explicit validation. If future requirements demand stricter constraints (like non-empty titles, etc.), you might need pre-upload checks or initialization-time guards to avoid invalid data in Firestore.

Data/Data/DI/AppAssembly.swift (1)

94-97: Repository instantiation considerations.
FeedbackRepository is registered in .container scope as well. Ensure a global single instance is intended. Otherwise, you risk collisions or concurrency issues when multiple distinct feedback flows occur simultaneously.

Data/Data/Helper/Firebase/StorageManager.swift (3)

17-17: Consider renaming for clarity.
While adding case feedback is perfectly valid, consider renaming the enum from ImageStoreType to something more general, like MediaStoreType, since it now supports other attachment types.


54-69: Improve error handling and resiliency.
The uploadAttachment implementation is straightforward. However, consider adding retry logic or partial failure handling for network hiccups when uploading attachments.


81-83: Rename log messages consistently.
Inside deleteAttachment, the log reads “Image deleted successfully.” For consistency, rename references from "Image" to "Attachment" to avoid confusion.

Splito/UI/Home/Account/AccountHomeViewModel.swift (1)

36-46: Remove or justify the commented-out email code.
Since you have replaced the email composition with a direct push to .FeedbackView, the commented-out email logic appears obsolete. Removing dead code helps keep the codebase clean.

Splito/UI/Home/Account/Feedback/FeedbackViewModel.swift (3)

50-61: Validate feedback structure before sending

The submit logic checks isValidTitle, but consider validating the maximum video size or multiple attachment conditions here too, so the user receives immediate feedback if the attachments are invalid.


134-168: Title vs. description naming confusion

The variable titleText in FeedbackDescriptionView might be better named descriptionText or something more descriptive, so it doesn’t conflict with the concept of “title” used elsewhere.


183-202: Recovery steps upon upload failure

The logic to add the failed attachment to failedAttachments is good, but consider providing user-facing feedback (toast or alert) if the upload consistently fails or retry attempts are exhausted.

Splito/Localization/Localizable.xcstrings (2)

170-172: Ensure localized value for "Add attachment".
There's no visible string value for the Add attachment key. If you plan to show user-facing text, please add the localized value.


280-280: Refine the grammar in the "Choose mode" string.
"Please choose your preferred mode to includes attachment..." has a grammatical issue. Consider updating it:

- "Choose mode\n Please choose your preferred mode to includes attachment with feedback"
+ "Choose mode\n Please choose your preferred mode to include attachments with feedback"
Splito.xcodeproj/project.pbxproj (1)

347-355: Logical grouping for Feedback module.
Creating a dedicated "Feedback" group is a good way to maintain code organization. Just ensure any related files, like tests or assets for feedback, are also included in this folder for consistency.

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between a4fd1fc and a485008.

📒 Files selected for processing (29)
  • BaseStyle/BaseStyle.xcodeproj/project.pbxproj (4 hunks)
  • BaseStyle/BaseStyle/CustomUI/MediaPickerOptionsView.swift (1 hunks)
  • BaseStyle/BaseStyle/Extension/UIImage+Extension.swift (1 hunks)
  • Data/Data.xcodeproj/project.pbxproj (8 hunks)
  • Data/Data/DI/AppAssembly.swift (2 hunks)
  • Data/Data/Helper/Firebase/StorageManager.swift (2 hunks)
  • Data/Data/Model/Feedback.swift (1 hunks)
  • Data/Data/Repository/ExpenseRepository.swift (2 hunks)
  • Data/Data/Repository/FeedbackRepository.swift (1 hunks)
  • Data/Data/Repository/GroupRepository.swift (2 hunks)
  • Data/Data/Repository/TransactionRepository.swift (2 hunks)
  • Data/Data/Repository/UserRepository.swift (2 hunks)
  • Data/Data/Router/AppRoute.swift (2 hunks)
  • Data/Data/Store/FeedbackStore.swift (1 hunks)
  • Data/Data/Utils/DeviceInfo.swift (1 hunks)
  • Splito.xcodeproj/project.pbxproj (5 hunks)
  • Splito/Localization/Localizable.xcstrings (4 hunks)
  • Splito/UI/Home/Account/AccountHomeViewModel.swift (1 hunks)
  • Splito/UI/Home/Account/AccountRouteView.swift (1 hunks)
  • Splito/UI/Home/Account/Feedback/FeedbackView.swift (1 hunks)
  • Splito/UI/Home/Account/Feedback/FeedbackViewModel.swift (1 hunks)
  • Splito/UI/Home/Account/User Profile/UserProfileView.swift (1 hunks)
  • Splito/UI/Home/Account/User Profile/UserProfileViewModel.swift (1 hunks)
  • Splito/UI/Home/ActivityLog/ActivityLogView.swift (1 hunks)
  • Splito/UI/Home/Expense/AddExpenseView.swift (1 hunks)
  • Splito/UI/Home/Expense/AddExpenseViewModel.swift (1 hunks)
  • Splito/UI/Home/Groups/Create Group/CreateGroupView.swift (1 hunks)
  • Splito/UI/Home/Groups/Create Group/CreateGroupViewModel.swift (1 hunks)
  • Splito/UI/Home/Groups/Group/Group Options/Settle up/Payment/GroupPaymentViewModel.swift (1 hunks)
✅ Files skipped from review due to trivial changes (2)
  • Splito/UI/Home/Expense/AddExpenseView.swift
  • Splito/UI/Home/Groups/Group/Group Options/Settle up/Payment/GroupPaymentViewModel.swift
🔇 Additional comments (48)
Data/Data/Repository/UserRepository.swift (2)

47-49: Consistent method renaming and reference update.

Replacing uploadImage with uploadAttachment and imageData with attachmentData here is consistent with the new naming convention across the codebase. The usage of try await is properly handled for concurrency. This looks good overall.


64-65: Validate return value handling on deletion.

You're discarding the return value of deleteAttachment by using _ = try await. Confirm that this function’s return (if any) is safe to ignore. If you need to verify successful deletion beyond catching thrown errors, consider capturing and checking the returned value instead of ignoring it.

Splito/UI/Home/Expense/AddExpenseViewModel.swift (2)

216-219: LGTM! Good memory management practice.

Using [weak self] in the animation closure prevents potential retain cycles, which is especially important in asynchronous contexts.


220-220: Implement or document the .removeAll case.

The .removeAll case is currently empty. If this is intended for future use, please add a TODO comment explaining the planned functionality. If it's required for consistency with other view models but not applicable here, document why it's intentionally empty.

Let's check if other view models have implemented this case:

Splito/UI/Home/Account/User Profile/UserProfileView.swift (1)

102-102: Verify proper handling of new media picker features and usage consistency

Replacing ImagePickerOptionsView with MediaPickerOptionsView suggests expanded capability for handling attachments (e.g., videos). Ensure that the rest of the code (including handleActionSelection) properly supports these additional media types, and confirm that validation and UI feedback are appropriate.

Here is a script that searches for usage of MediaPickerOptionsView throughout the repository to confirm consistent handling and usage:

✅ Verification successful

Let me gather more information about the implementation of MediaPickerOptionsView and its handler.


Let me check one more thing to verify the ActionsOfSheet enum and its cases.


MediaPickerOptionsView implementation is consistent and properly supported

Based on the verification:

  • The MediaPickerOptionsView is consistently used across multiple views (UserProfile, Feedback, AddExpense, CreateGroup)
  • All implementations properly handle the media picker actions through handleActionSelection callbacks
  • The ActionsOfSheet enum supports camera, gallery, remove, and removeAll actions
  • Each view model implements the handler with appropriate permission checks and state management
  • No expanded media types (like video) are actually introduced - it's still focused on image picking functionality

The rename from ImagePickerOptionsView to MediaPickerOptionsView appears to be just a naming improvement for consistency, without actually introducing new media type support. All implementations are consistent with this usage.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify usage of MediaPickerOptionsView across the codebase

rg -A 5 "MediaPickerOptionsView"

Length of output: 6774


Script:

#!/bin/bash
# Check the implementation of MediaPickerOptionsView and its handler types
ast-grep --pattern 'struct MediaPickerOptionsView {
  $$$
}'

# Check for handleActionSelection implementations
rg -A 5 "handleActionSelection.*\{" 

Length of output: 3835


Script:

#!/bin/bash
# Check the ActionsOfSheet enum definition
rg -A 5 "enum ActionsOfSheet"

Length of output: 478

Data/Data/Store/FeedbackStore.swift (1)

14-14: Ensure Firestore is initialized properly.
If there is any chance that Firestore is not yet configured before use, consider exposing a public initializer or validating the database reference before accessing feedbacksCollection.

Data/Data/Repository/FeedbackRepository.swift (1)

16-18: Capture potential errors from Firestore operations.
The addFeedback call may fail silently if not properly handled after propagation. Ensure calling sites handle possible throwing errors or implement a retry/QoS strategy.

Data/Data/DI/AppAssembly.swift (1)

64-67: Scope verification.
You're registering FeedbackStore in .container scope, which might be correct if you need a single store instance across the entire app. Confirm that a single instance suits all usage patterns; otherwise, consider a different scope (e.g., .transient) to avoid unexpected shared states.

Data/Data/Helper/Firebase/StorageManager.swift (4)

29-33: Verify the storage path correctness.
The path is set to "feedback_attachments". Ensure that this aligns with expected Firebase storage folder structures and naming conventions across the codebase.


35-39: Enum naming clarity.
AttachmentType is a clear addition, and each case is well-defined. No issues noted.


40-47: Validate content type matching.
Although "image/jpg" typically works, many systems expect "image/jpeg". Similarly, ensure "video/mp4" is correct for your typical video files and that application/octet-stream suffices for other attachments.


75-78: Double-check concurrency approach.
Deleting the old file before uploading a new one can lead to temporary unavailability if something fails during the upload. Consider uploading first, then deleting if the upload succeeds, to reduce downtime or data loss concerns.

Data/Data/Router/AppRoute.swift (2)

50-50: Feedback route case.
The new FeedbackView route is a clear addition that aligns with the broader feedback feature.


107-108: Consistent route key naming.
"feedbackView" consistently follows the naming pattern of other route keys.

Splito/UI/Home/Groups/Create Group/CreateGroupView.swift (1)

123-123: Updated media picker component.
Replacing ImagePickerOptionsView with MediaPickerOptionsView is consistent with the expanded media capabilities. No further issues noted.

Data/Data/Repository/ExpenseRepository.swift (2)

53-53: Good alignment with the new attachment deletion strategy

Renaming deleteImage to deleteAttachment ensures consistent terminology across the codebase. This improves clarity and maintainability. The usage here looks correct.


66-66: Check for null or invalid response from uploadAttachment

Even though you return a default value "" if uploadAttachment returns nil, consider adding a check or logging in case an unexpected empty string is returned, to help diagnose possible failures more quickly.

Data/Data/Repository/GroupRepository.swift (2)

61-61: Rename usage validated

Switching from deleteImage to deleteAttachment is consistent with the new approach. No action needed here.


86-86: Same note on potential nil return

Like in ExpenseRepository.swift, ensure you handle or log the case where uploadAttachment returns nil, helping track unexpected failures.

Splito/UI/Home/Account/Feedback/FeedbackViewModel.swift (5)

16-18: Good use of dependency injection

Injecting preference and feedbackRepository keeps the view model clean and testable. This is a good practice.


20-22: Consider potential concurrency concerns

Set<String> is published. If multiple tasks manipulate uploadedAttachmentIDs concurrently, consider using concurrency-safe operations. Swift’s @Published helps with reentrant reads, but you might need a dedicated queue or actor if concurrency complexity increases.


40-46: Router injection is an effective approach

Passing in router from outside allows for loose coupling. This design provides clarity and fosters better test coverage.


66-80: Robust error handling in async call

Having a do/catch block for feedbackRepository.addFeedback is good. If there's additional cleanup or partial rollback needed upon failure (e.g., removing any successfully uploaded attachments), consider adding it here.


168-181: Video size check is implemented well

The fallback for removing the oversized video from selectedAttachments and showing a toast is consistent with best UX patterns. Good job handling the error scenario here.

Splito/UI/Home/Account/Feedback/FeedbackView.swift (2)

16-18: Excellent use of ObservedObject

This properly connects view state to the FeedbackViewModel. Code is straightforward and easy to follow.


58-60: Keyboard dismissal approach is user-friendly

Allowing interactive dismissal of the keyboard is convenient for mobile apps. This helps ensure a seamless user experience.

Splito/Localization/Localizable.xcstrings (2)

6-8: Consider clarifying the key " " usage.
An empty key with a space, and no localized string, might be confusing. Ensure this placeholder is intentional and documented to avoid confusion.


891-893: Verify the new "Title" string usage.
The new key "Title" may need a corresponding localized value. Ensure it's properly used in the UI and tested.

BaseStyle/BaseStyle.xcodeproj/project.pbxproj (4)

12-12: New build file for MediaPickerOptionsView.swift
This looks correct. Verify that the file belongs to the intended build targets and that the rest of your references (e.g., Import statements) are in place.


75-75: File reference configured correctly
The addition of MediaPickerOptionsView.swift in the file references is consistent with standard Xcode project practices.


311-311: Grouped under CustomUI
Placing MediaPickerOptionsView.swift under CustomUI aligns logically with the other custom UI components. Looks good.


527-527: Included in PBXSourcesBuildPhase
The file is included in the Sources build phase, ensuring it compiles. No issues found.

Data/Data.xcodeproj/project.pbxproj (10)

14-17: New Feedback-related build files
The additions of Feedback.swift, DeviceInfo.swift, FeedbackStore.swift, and FeedbackRepository.swift seem properly set up. Ensure relevant tests are added.


78-81: File references for new feedback modules
All references for Feedback.swift, DeviceInfo.swift, FeedbackStore.swift, and FeedbackRepository.swift are properly declared.


191-191: Repository grouping
FeedbackRepository.swift is logically placed in the Repository group. Nice organization.


205-205: Model grouping
Feedback.swift is added to Model, which makes sense. Good clarity.


215-215: DeviceInfo in Utils
DeviceInfo.swift is in the Utils folder, consistent with a utility role.


262-262: Store grouping
FeedbackStore.swift is suitably placed in Store. Project structure remains consistent.


548-548: DeviceInfo in the Sources build phase
Confirmed that DeviceInfo.swift is added to compilation. No issues found.


553-553: Feedback model in the Sources build phase
The new Feedback.swift is included for compilation. All good.


561-561: FeedbackRepository in the Sources build phase
FeedbackRepository.swift is referenced correctly.


573-573: FeedbackStore in the Sources build phase
FeedbackStore.swift is included to be built. Implementation details look fine.

Data/Data/Repository/TransactionRepository.swift (1)

59-59: Method signature accurately updated to deleteAttachment.

Renaming from deleteImage to deleteAttachment is consistent with the broader attachment handling approach. Good job on aligning the terminology.

Splito.xcodeproj/project.pbxproj (5)

20-21: New build file references for feedback feature.
These additions correctly reference and include the new FeedbackView.swift and FeedbackViewModel.swift in Sources. Everything looks good from a build file perspective.


167-168: File references are properly set.
These lines properly register the newly added Swift files for feedback handling. The path and file type attributes for .swift sources appear correctly.


661-661: Verify grouping under "Account."
Adding "Feedback" inside the "Account" group might be appropriate if feedback is account-specific. However, if it has broader scope, consider placing it at a higher level for better discoverability.


1114-1114: Sources build phase entry for FeedbackViewModel.
This entry ensures that FeedbackViewModel is compiled. No issues noted.


1119-1119: Sources build phase entry for FeedbackView.
Similarly, this ensures FeedbackView is compiled. Looks good.

Data/Data/Utils/DeviceInfo.swift Outdated Show resolved Hide resolved
Data/Data/Utils/DeviceInfo.swift Outdated Show resolved Hide resolved
Data/Data/Model/Feedback.swift Outdated Show resolved Hide resolved
Splito/UI/Home/Account/Feedback/FeedbackViewModel.swift Outdated Show resolved Hide resolved
Splito/UI/Home/Account/Feedback/FeedbackView.swift Outdated Show resolved Hide resolved
Copy link

@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: 3

🧹 Nitpick comments (9)
BaseStyle/BaseStyle/CustomUI/Buttons/DismissButton.swift (1)

20-24: Consider using a configuration object pattern for better maintainability.

While the initializer is functionally correct, it has many parameters which could make it harder to maintain as more customization options are added. Consider refactoring using a configuration object pattern.

Here's a suggested approach:

public struct DismissButtonConfiguration {
    let iconName: String
    let iconSize: (CGFloat, weight: Font.Weight)
    let padding: (horizontal: CGFloat, vertical: CGFloat)
    let borderColor: Color
    let foregroundColor: Color
    let backgroundColor: Color?
    
    public static let `default` = DismissButtonConfiguration(
        iconName: "multiply",
        iconSize: (24, .regular),
        padding: (0, 0),
        borderColor: .clear,
        foregroundColor: secondaryText,
        backgroundColor: nil
    )
}

public init(
    configuration: DismissButtonConfiguration = .default,
    onDismissAction: (() -> Void)? = nil
)

This approach would:

  • Improve readability
  • Make it easier to add new customization options
  • Provide a clear default configuration
  • Reduce parameter count in the initializer
Splito/UI/Home/Account/Feedback/FeedbackViewModel.swift (5)

13-14: Consider moving constants to a configuration file

The VIDEO_SIZE_LIMIT_IN_BYTES and TITLE_CHARACTER_MIN_LIMIT constants should be moved to a configuration file or settings bundle for easier maintenance and potential runtime configuration.


19-33: Add documentation for public properties

Consider adding documentation comments for published properties to explain their purpose and usage. This will improve code maintainability and help other developers understand the view model's state management.

Example:

/// The user's feedback description text
@Published var description: String = ""

/// The current state of the feedback view
@Published private(set) var currentState: ViewState = .initial

57-60: Consider extracting device information collection

The device information collection logic could be moved to a separate utility class for better separation of concerns and reusability.

Example:

struct DeviceInfoProvider {
    static func getCurrentDeviceInfo() -> (appVersion: String, deviceName: String, osVersion: String) {
        return (
            DeviceInfo.appVersionName,
            UIDevice.current.name,
            UIDevice.current.systemVersion
        )
    }
}

168-181: Add upload progress tracking

Consider implementing upload progress tracking to provide better user feedback during file uploads.

Example:

private func upload(attachment: Attachment) {
    // ... existing code ...
    if let data = attachment.videoData {
        let progress = Progress(totalUnitCount: Int64(data.count))
        // Implement progress tracking
        progress.addObserver(self, forKeyPath: "fractionCompleted", options: .new, context: nil)
    }
}

207-210: Enhance ViewState enum

Consider adding more states to better represent the view's lifecycle, such as uploading, submitting, error, etc.

enum ViewState {
    case initial
    case loading
    case uploading(progress: Double)
    case submitting
    case error(String)
    case success
}
Splito/UI/Home/Account/Feedback/FeedbackView.swift (3)

58-61: Consider extracting keyboard dismiss mode setup to a view modifier

The keyboard dismiss mode setup could be extracted to a reusable view modifier for better code organization.

Create a custom view modifier:

struct KeyboardDismissModeModifier: ViewModifier {
    func body(content: Content) -> some View {
        content.onAppear {
            UIScrollView.appearance().keyboardDismissMode = .interactive
        }
    }
}

extension View {
    func interactiveKeyboardDismissMode() -> some View {
        modifier(KeyboardDismissModeModifier())
    }
}

Then use it like:

- .onAppear {
-     focusField = .title
-     UIScrollView.appearance().keyboardDismissMode = .interactive
- }
+ .onAppear {
+     focusField = .title
+ }
+ .interactiveKeyboardDismissMode()

124-130: Remove duplicate foregroundColor modifier

The text view has duplicate foregroundColor modifiers.

Apply this diff:

Text(shouldShowValidationMessage ? (isValidTitle ? " " : "Minimum 3 characters are required") : " ")
    .foregroundColor(errorColor)
    .font(.body1(12))
-   .foregroundColor(errorColor)
    .minimumScaleFactor(0.5)
    .lineLimit(1)

319-321: Consider adding configuration for supported media types

The picker configuration could be more specific about supported media types and file size limits.

Apply this diff:

var configuration = PHPickerConfiguration()
configuration.selectionLimit = 10
+ configuration.filter = .any(of: [
+     .images,
+     .videos(matching: [
+         UTType.quickTimeMovie.identifier,
+         UTType.mpeg4Movie.identifier
+     ])
+ ])
+ configuration.preferredAssetRepresentationMode = .current
let picker = PHPickerViewController(configuration: configuration)
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between a485008 and b6fadaa.

📒 Files selected for processing (4)
  • BaseStyle/BaseStyle/CustomUI/Buttons/DismissButton.swift (2 hunks)
  • Splito/Localization/Localizable.xcstrings (4 hunks)
  • Splito/UI/Home/Account/Feedback/FeedbackView.swift (1 hunks)
  • Splito/UI/Home/Account/Feedback/FeedbackViewModel.swift (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • Splito/Localization/Localizable.xcstrings
🔇 Additional comments (3)
BaseStyle/BaseStyle/CustomUI/Buttons/DismissButton.swift (1)

12-12: LGTM! Well-structured property declaration.

The new iconName property follows Swift naming conventions and has appropriate access level modifiers.

Splito/UI/Home/Account/Feedback/FeedbackViewModel.swift (1)

105-121: ⚠️ Potential issue

Fix potential race condition in deleteAttachment

The current implementation has a potential race condition when removing items from multiple collections. The index used to remove from uploadingAttachments may be invalid after removing from selectedAttachments.

- self.uploadingAttachments.removeAll { $0.id == self.selectedAttachments[index].id }
+ self.uploadingAttachments.removeAll { $0.id == attachment.id }

Likely invalid or redundant comment.

Splito/UI/Home/Account/Feedback/FeedbackView.swift (1)

71-74: Prevent direct reference to function arguments in the sheet init

The sheet presentation still directly references the function argument which could cause immediate execution.

Apply this diff to fix the issue:

.sheet(isPresented: $viewModel.showMediaPicker) {
-    MultipleMediaSelectionPickerView(isPresented: $viewModel.showMediaPicker,
-                                    onDismiss: viewModel.onMediaPickerSheetDismiss(attachments:))
+    MultipleMediaSelectionPickerView(isPresented: $viewModel.showMediaPicker,
+                                    onDismiss: { attachments in
+                                        viewModel.onMediaPickerSheetDismiss(attachments: attachments)
+                                    })
}

Copy link

@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 (9)
Splito/UI/Home/Account/Feedback/MultiMediaSelectionPickerView.swift (4)

24-26: Clarify selection limit.
The configuration.selectionLimit = 10 is a good approach to limit the number of items that can be picked.

Consider whether 10 items is an intentional product requirement or if it should be configurable for future reuse.


56-56: Asynchronous image loading suggestion.
Using imageRequestOptions.isSynchronous = true blocks the thread while loading images. Consider using asynchronous loading to prevent potential UI thread blocking.


62-65: Add error-handling or fallback image.
If image loading fails, you log the error and move on. Consider providing a fallback (e.g., placeholder image) or user-facing error message so users know something went wrong.


55-92: Consider concurrency for loading tasks.
You are using a DispatchGroup for concurrency, but each itemProvider load calls the main queue dispatch afterwards. If the total items are large, consider if off-main-queue runs can improve performance.

Splito/UI/Home/Account/AccountHomeViewModel.swift (2)

30-31: Consider adding error handling for routing failures.

While the implementation is clean and focused, consider handling potential routing failures to maintain a robust user experience. This is especially important as this is a user-facing support feature.

 func onContactSupportTap() {
-    router.push(.FeedbackView)
+    do {
+        try router.push(.FeedbackView)
+    } catch {
+        showToastFor(toast: ToastPrompt(
+            type: .error,
+            title: "Error",
+            message: "Unable to open feedback form. Please try again."
+        ))
+        LogE("AccountHomeViewModel: Failed to open feedback view - \(error)")
+    }
 }

Line range hint 13-92: Great architectural improvements!

The shift from email-based contact to a dedicated feedback system has improved the code architecture by:

  • Reducing external dependencies
  • Simplifying the user flow
  • Maintaining consistency with existing patterns
  • Following MVVM architecture with clear separation of concerns

The implementation aligns well with the existing dependency injection, routing, and state management patterns in the codebase.

Splito/UI/Home/Account/Feedback/FeedbackViewModel.swift (3)

13-14: Extract constants to a configuration file

Consider moving these constants to a dedicated configuration file or enum for better maintainability. Also, the video size limit should use byte-size literals for better readability.

- private let VIDEO_SIZE_LIMIT_IN_BYTES = 5000000 // 5 MB
+ private let VIDEO_SIZE_LIMIT_IN_BYTES = 5 * 1024 * 1024 // 5 MB

19-32: Group related published properties

Consider organizing related properties using private nested types for better code organization and maintainability. This will help manage the growing number of state variables.

private struct ViewState {
    var description: String = ""
    var title: String = ""
    var currentState: State = .initial
    var showLoader: Bool = false
    // ... other view state properties
}

@Published private var state: ViewState

57-60: Extract device information collection to a utility class

Consider moving device information collection logic to a dedicated utility class for better separation of concerns and reusability.

struct DeviceInfoProvider {
    static func getCurrentDeviceInfo() -> DeviceInfo {
        return DeviceInfo(
            appVersion: DeviceInfo.appVersionName,
            deviceName: UIDevice.current.name,
            deviceOsVersion: UIDevice.current.systemVersion
        )
    }
}
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between b6fadaa and ff2d71c.

📒 Files selected for processing (10)
  • BaseStyle/BaseStyle.xcodeproj/project.pbxproj (4 hunks)
  • BaseStyle/BaseStyle/CustomUI/MailComposeView.swift (0 hunks)
  • Data/Data/Utils/DeviceInfo.swift (1 hunks)
  • Splito.xcodeproj/project.pbxproj (6 hunks)
  • Splito/Localization/Localizable.xcstrings (5 hunks)
  • Splito/UI/Home/Account/AccountHomeView.swift (2 hunks)
  • Splito/UI/Home/Account/AccountHomeViewModel.swift (2 hunks)
  • Splito/UI/Home/Account/Feedback/FeedbackView.swift (1 hunks)
  • Splito/UI/Home/Account/Feedback/FeedbackViewModel.swift (1 hunks)
  • Splito/UI/Home/Account/Feedback/MultiMediaSelectionPickerView.swift (1 hunks)
💤 Files with no reviewable changes (1)
  • BaseStyle/BaseStyle/CustomUI/MailComposeView.swift
🚧 Files skipped from review as they are similar to previous changes (3)
  • Data/Data/Utils/DeviceInfo.swift
  • Splito/Localization/Localizable.xcstrings
  • Splito/UI/Home/Account/Feedback/FeedbackView.swift
🔇 Additional comments (11)
BaseStyle/BaseStyle.xcodeproj/project.pbxproj (1)

12-12: LGTM! Project configuration changes look good.

The integration of MediaPickerOptionsView.swift into the project is properly configured:

  • File references are correctly added with consistent identifiers
  • File is appropriately placed in the CustomUI group
  • Build phases are properly updated

Also applies to: 74-74, 308-308, 523-523

Splito/UI/Home/Account/AccountHomeView.swift (2)

29-29: Method reference updated to onContactSupportTap

Renaming from onContactUsTap to onContactSupportTap is clear and consistent with the new feature's purpose.


117-117: Label text changed to "Contact Support"

Renaming “Contact Us” to “Contact Support” more accurately reflects the updated functionality. No concerns here.

Splito/UI/Home/Account/Feedback/MultiMediaSelectionPickerView.swift (1)

29-29: Ensure consistent theming.
You're manually setting picker.view.tintColor = UIColor(infoColor). If your project uses a dynamic theming system, confirm that this approach won't conflict with global styling.

Splito.xcodeproj/project.pbxproj (5)

20-22: Approved addition of Feedback files.
Adding FeedbackView.swift, FeedbackViewModel.swift, and MultiMediaSelectionPickerView.swift to the build phases ensures they will be compiled and packaged.


168-170: File references are set correctly.
These lines accurately reference the new files in the PBXFileReference section, aligning them with the project structure.


349-358: Appropriate grouping for new Feedback files.
Creating a dedicated Feedback group in the Xcode project helps maintain clarity and organization.


666-666: Confirmed integration into Account folder.
Inclusion of the Feedback group under Account ensures logical categorization in your folder hierarchy.


1092-1092: Correctly added to sources build phase.
The new files (MultiMediaSelectionPickerView.swift, FeedbackViewModel.swift, FeedbackView.swift) are properly listed under the PBXSourcesBuildPhase. They will be compiled with the rest of the Swift code.

Also applies to: 1118-1118, 1123-1123

Splito/UI/Home/Account/AccountHomeViewModel.swift (2)

10-10: LGTM! UIKit import is appropriately placed.

The UIKit import is necessary for URL handling and application operations used throughout the class.


Line range hint 1-92: Verify cleanup of email-related functionality.

Let's ensure all email-related code has been properly removed from the codebase.

✅ Verification successful

Let me perform additional verification to check for any remaining email-related code, particularly focusing on the contact functionality changes.


Let me check the FeedbackView implementation to understand how the contact functionality is now handled.


Email functionality has been properly replaced with in-app feedback system.

The email-based contact functionality has been completely replaced with a new in-app feedback system that:

  • Allows users to submit feedback with title and description
  • Supports attachments (images and videos)
  • Handles file uploads to storage
  • Stores feedback in the database with device information
  • Shows appropriate success/error messages

The cleanup is complete with no remaining email-related code in the contact flow. The only email-related code that exists is for user authentication purposes, which is separate from the contact functionality.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for any remaining references to email-related functionality

# Check for MFMailCompose references
echo "Checking for MFMailCompose references..."
rg -i "MFMailCompose|MailComposeView|canSendMail"

# Check for email-related strings
echo "Checking for email-related strings..."
rg -i "Contact Us|showMailToast|onContactUsTap"

# Check for any remaining email validation or handling
echo "Checking for email handling..."
rg -i "mailto:|MFMailComposeResult|mailComposeController"

Length of output: 1339


Script:

#!/bin/bash
# Search for contact-related functionality in the codebase

# Check for contact/support related methods and strings
echo "Checking for contact/support related code..."
rg -i "contact.*support|support.*contact|feedback.*support"

# Check for any email validation or patterns
echo "Checking for email patterns..."
rg -i "email.*validation|validate.*email|email.*pattern"

# Look for any remaining mail-related imports
echo "Checking for mail-related imports..."
rg -i "import.*MessageUI"

# Check for specific feedback view implementation
echo "Checking FeedbackView implementation..."
fd -e swift "FeedbackView"

Length of output: 43065


Script:

#!/bin/bash
# Check the implementation of FeedbackView and related files

echo "Checking FeedbackView implementation..."
cat Splito/UI/Home/Account/Feedback/FeedbackView.swift

echo -e "\nChecking FeedbackViewModel implementation..."
cat Splito/UI/Home/Account/Feedback/FeedbackViewModel.swift

Length of output: 20006

Copy link

@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: 3

🧹 Nitpick comments (2)
functions/src/contact_support_service/contact_support_service.ts (1)

28-32: Avoid hardcoding email addresses.
It’s better to fetch recipient and sender addresses from environment variables or a secure configuration to avoid future code changes in case the email addresses change. It also improves security and maintainability.

functions/src/mail_service/mail_service.ts (1)

54-59: Surface error context for more robust debugging.
When an email fails to send, you log the error and re-throw a generic error message. You might want to propagate additional details in a controlled manner to help debugging (e.g., the result of sesClient if available).

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between ff2d71c and 793c04f.

⛔ Files ignored due to path filters (1)
  • firebase-debug.log is excluded by !**/*.log
📒 Files selected for processing (4)
  • functions/package.json (1 hunks)
  • functions/src/contact_support_service/contact_support_service.ts (1 hunks)
  • functions/src/index.ts (2 hunks)
  • functions/src/mail_service/mail_service.ts (1 hunks)
🔇 Additional comments (2)
functions/src/mail_service/mail_service.ts (1)

7-12: Double-check AWS credentials handling.
You correctly fail fast if credentials are missing. However, ensure you also review how these credentials are stored in Firebase config (e.g. applying least privilege if possible, limiting the IAM role specifically to SES usage).

functions/package.json (1)

19-19: Keep an eye on @aws-sdk/client-ses for security updates.
Pinned dependencies help avoid breaking changes, but ensure you routinely check for new versions or security patches in the AWS SDK as vulnerabilities and improvements are discovered.

Copy link

@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: 4

♻️ Duplicate comments (1)
Splito/UI/Home/Account/Feedback/MultiMediaSelectionPickerView.swift (1)

74-91: ⚠️ Potential issue

Improve temporary file handling for videos.

The temporary URL provided by loadFileRepresentation is only valid during the callback. The current implementation might lead to accessing invalid URLs.

Consider this safer approach:

 attachment.itemProvider.loadFileRepresentation(forTypeIdentifier: UTType.movie.identifier) { url, error in
     if let url = url, let fileName = attachment.itemProvider.suggestedName {
         do {
             let data = try Data(contentsOf: url)
+            // Create a permanent URL in the app's temporary directory
+            let permanentURL = FileManager.default.temporaryDirectory
+                .appendingPathComponent(UUID().uuidString)
+                .appendingPathExtension("mov")
+            try data.write(to: permanentURL)
-            let videoObject = Attachment(videoData: data, video: url, name: fileName)
+            let videoObject = Attachment(videoData: data, video: permanentURL, name: fileName)
             attachments.append(videoObject)
         } catch {
             LogE("MultiMediaSelectionPickerCoordinator: \(#function) Error loading data from URL: \(error)")
         }
     }
     // ... rest of the code
 }
🧹 Nitpick comments (7)
Splito/UI/Home/Account/Feedback/MultiMediaSelectionPickerView.swift (3)

13-22: Add documentation for public interface.

Consider adding documentation comments for the public struct and its initializer to improve API clarity. This is especially important for reusable components.

Add documentation like this:

+/// A SwiftUI view that presents a media picker supporting multiple image and video selections.
 public struct MultiMediaSelectionPickerView: UIViewControllerRepresentable {
+    /// Binding to control the presentation state of the picker.
     @Binding var isPresented: Bool
 
+    /// Closure called when media selection is complete, providing an array of selected attachments.
     let onDismiss: ([Attachment]) -> Void
 
+    /// Creates a new media picker view.
+    /// - Parameters:
+    ///   - isPresented: Binding to control the picker's presentation state
+    ///   - onDismiss: Closure called with selected attachments when picker is dismissed
     public init(isPresented: Binding<Bool>, onDismiss: @escaping ([Attachment]) -> Void) {

24-40: Consider making configuration more flexible.

The selection limit is currently hardcoded to 5. Consider making this configurable through the initializer to improve reusability.

Here's how you could improve it:

 public struct MultiMediaSelectionPickerView: UIViewControllerRepresentable {
     @Binding var isPresented: Bool
     let onDismiss: ([Attachment]) -> Void
+    let selectionLimit: Int
 
-    public init(isPresented: Binding<Bool>, onDismiss: @escaping ([Attachment]) -> Void) {
+    public init(isPresented: Binding<Bool>, selectionLimit: Int = 5, onDismiss: @escaping ([Attachment]) -> Void) {
         self._isPresented = isPresented
+        self.selectionLimit = selectionLimit
         self.onDismiss = onDismiss
     }
 
     public func makeUIViewController(context: Context) -> PHPickerViewController {
         var configuration = PHPickerConfiguration()
-        configuration.selectionLimit = 5
+        configuration.selectionLimit = selectionLimit

67-67: Specify image resize parameters.

The resizeImageIfNeededWhilePreservingAspectRatio() method is called without specific size limits. Consider adding maximum dimensions to prevent memory issues with large images.

-let imageObject = Attachment(image: selectedImage.resizeImageIfNeededWhilePreservingAspectRatio(), name: fileName)
+let imageObject = Attachment(image: selectedImage.resizeImageIfNeededWhilePreservingAspectRatio(maxDimension: 2048), name: fileName)
Splito/UI/Home/Account/Feedback/FeedbackViewModel.swift (4)

13-15: Extract magic numbers into documented constants

Consider moving these magic numbers into a configuration enum or struct with proper documentation explaining the rationale behind these limits.

-    private let TITLE_CHARACTER_MIN_LIMIT = 3
-    private let VIDEO_SIZE_LIMIT_IN_BYTES = 5000000 // 5 MB
-    private let IMAGE_SIZE_LIMIT_IN_BYTES = 3000000 // 3 MB
+    private enum Constraints {
+        /// Minimum number of characters required for feedback title
+        static let titleMinLength = 3
+        
+        /// Maximum video size (5 MB) to ensure optimal storage and loading
+        static let maxVideoSize = 5 * 1024 * 1024
+        
+        /// Maximum image size (3 MB) to ensure optimal storage and loading
+        static let maxImageSize = 3 * 1024 * 1024
+        
+        /// Maximum number of attachments allowed per feedback
+        static let maxAttachments = 5
+    }

57-60: Extract device info collection into a separate utility

Consider moving the device info collection logic into a dedicated utility class to improve modularity and reusability.

+ struct DeviceInfoProvider {
+     static func getCurrentDeviceInfo() -> (appVersion: String, deviceName: String, osVersion: String) {
+         return (
+             DeviceInfo.appVersionName,
+             UIDevice.current.name,
+             UIDevice.current.systemVersion
+         )
+     }
+ }

-        let feedback = Feedback(title: title, description: description, userId: userId,
-                                attachmentUrls: attachmentsUrls.map { $0.url }, appVersion: DeviceInfo.appVersionName,
-                                deviceName: UIDevice.current.name, deviceOsVersion: UIDevice.current.systemVersion)
+        let deviceInfo = DeviceInfoProvider.getCurrentDeviceInfo()
+        let feedback = Feedback(
+            title: title,
+            description: description,
+            userId: userId,
+            attachmentUrls: attachmentsUrls.map { $0.url },
+            appVersion: deviceInfo.appVersion,
+            deviceName: deviceInfo.deviceName,
+            deviceOsVersion: deviceInfo.osVersion
+        )

194-198: Add exponential backoff for upload retries

Consider implementing an exponential backoff retry mechanism for failed uploads to handle temporary network issues.

+    private func uploadWithRetry(data: Data, attachment: Attachment, type: StorageManager.AttachmentType, retryCount: Int = 0) {
+        let maxRetries = 3
+        let backoffDelay = pow(2.0, Double(retryCount))
+        
+        Task { [weak self] in
+            do {
+                // ... existing upload code ...
+            } catch {
+                if retryCount < maxRetries {
+                    try? await Task.sleep(nanoseconds: UInt64(backoffDelay * 1_000_000_000))
+                    await self?.uploadWithRetry(data: data, attachment: attachment, type: type, retryCount: retryCount + 1)
+                } else {
+                    self?.failedAttachments.append(attachment)
+                    self?.uploadingAttachments.removeAll { $0.id == attachment.id }
+                    LogE("FeedbackViewModel: \(#function) Failed to upload attachment after \(maxRetries) retries: \(error)")
+                }
+            }
+        }
+    }

204-208: Localize error messages

Consider moving error messages to a localization file for better internationalization support.

+    private enum LocalizedError {
+        static let genericError = NSLocalizedString("Something went wrong", comment: "Generic error message")
+        static let attachmentRemovalError = NSLocalizedString("Failed to remove attachment", comment: "Attachment removal error")
+    }

     func handleError(message: String? = nil) {
         if let message {
-            showToastFor(toast: ToastPrompt(type: .error, title: "Error", message: message))
+            showToastFor(toast: ToastPrompt(type: .error, title: NSLocalizedString("Error", comment: "Error title"), message: message))
         } else {
             showToastForError()
         }
     }
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 793c04f and 8edb518.

📒 Files selected for processing (4)
  • Splito/Localization/Localizable.xcstrings (7 hunks)
  • Splito/UI/Home/Account/Feedback/FeedbackView.swift (1 hunks)
  • Splito/UI/Home/Account/Feedback/FeedbackViewModel.swift (1 hunks)
  • Splito/UI/Home/Account/Feedback/MultiMediaSelectionPickerView.swift (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • Splito/Localization/Localizable.xcstrings
  • Splito/UI/Home/Account/Feedback/FeedbackView.swift
🧰 Additional context used
🪛 SwiftLint (0.57.0)
Splito/UI/Home/Account/Feedback/FeedbackViewModel.swift

[Warning] 152-152: Lines should not have trailing whitespace

(trailing_whitespace)

🔇 Additional comments (4)
Splito/UI/Home/Account/Feedback/MultiMediaSelectionPickerView.swift (1)

1-12: LGTM! File structure and imports are well-organized.

The file includes all necessary framework imports and follows proper Swift conventions.

Splito/UI/Home/Account/Feedback/FeedbackViewModel.swift (3)

70-73: Fix potential retain cycle in alert closure

The closure capturing self could create a retain cycle.


82-87: Add validation for maximum attachments

Consider adding a limit to the number of attachments that can be added.


147-158: 🛠️ Refactor suggestion

Use synchronized access for attachment arrays

Multiple arrays are modified without synchronization, which could lead to race conditions in concurrent scenarios. Consider using a serial queue for array modifications.

+    private let attachmentQueue = DispatchQueue(label: "com.splito.attachment.queue")
+
     private func removeAttachmentFromArrays(attachmentId: String, removeAllSelected: Bool = false) {
-        withAnimation {
+        attachmentQueue.async { [weak self] in
+            guard let self = self else { return }
             attachmentsUrls.removeAll { $0.id == attachmentId }
             selectedAttachments.removeAll { $0.id == attachmentId }
             uploadingAttachments.removeAll { $0.id == attachmentId }
-            
+
             if removeAllSelected {
                 failedAttachments.removeAll { $0.id == attachmentId }
                 uploadedAttachmentIDs.remove(attachmentId)
             }
-        }
+            DispatchQueue.main.async {
+                withAnimation {}
+            }
+        }
     }

Likely invalid or redundant comment.

🧰 Tools
🪛 SwiftLint (0.57.0)

[Warning] 152-152: Lines should not have trailing whitespace

(trailing_whitespace)

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (3)
Splito/UI/Home/Account/Feedback/FeedbackViewModel.swift (3)

13-15: Improve constant naming and values

Consider using more descriptive names and byte notation for size limits:

-    private let TITLE_CHARACTER_MIN_LIMIT = 3
-    private let VIDEO_SIZE_LIMIT_IN_BYTES = 5000000 // 5 MB
-    private let IMAGE_SIZE_LIMIT_IN_BYTES = 3000000 // 3 MB
+    private let MIN_TITLE_LENGTH = 3
+    private let MAX_VIDEO_SIZE = 5 * 1024 * 1024  // 5 MB
+    private let MAX_IMAGE_SIZE = 3 * 1024 * 1024  // 3 MB

12-46: Add documentation for public interface

Consider adding documentation comments for the public interface to improve code maintainability:

+/// ViewModel responsible for managing user feedback submission and attachment handling
 class FeedbackViewModel: BaseViewModel, ObservableObject {
+    /// Minimum number of characters required for the feedback title
     private let TITLE_CHARACTER_MIN_LIMIT = 3
     
+    /// User's feedback description
     @Published var description: String = ""

56-59: Extract device info collection to a separate method

Consider extracting device info collection to improve readability and reusability:

+    private func getDeviceInfo() -> (appVersion: String, deviceName: String, osVersion: String) {
+        return (
+            appVersion: DeviceInfo.appVersionName,
+            deviceName: UIDevice.current.name,
+            osVersion: UIDevice.current.systemVersion
+        )
+    }

     let feedback = Feedback(title: title, description: description, userId: userId,
-        attachmentUrls: attachmentsUrls.map { $0.url }, appVersion: DeviceInfo.appVersionName,
-        deviceName: UIDevice.current.name, deviceOsVersion: UIDevice.current.systemVersion)
+        attachmentUrls: attachmentsUrls.map { $0.url },
+        appVersion: deviceInfo.appVersion,
+        deviceName: deviceInfo.deviceName,
+        deviceOsVersion: deviceInfo.osVersion)
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 8edb518 and 1074f4a.

📒 Files selected for processing (2)
  • Splito/UI/Home/Account/Feedback/FeedbackView.swift (1 hunks)
  • Splito/UI/Home/Account/Feedback/FeedbackViewModel.swift (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • Splito/UI/Home/Account/Feedback/FeedbackView.swift
🔇 Additional comments (2)
Splito/UI/Home/Account/Feedback/FeedbackViewModel.swift (2)

201-209: LGTM! Error handling looks good

The error handling implementation is clean and provides good flexibility with optional custom messages.


211-215: LGTM! Focus field enum is well-defined

The enum is simple and effectively serves its purpose for managing form field focus.

Splito/UI/Home/Account/Feedback/FeedbackViewModel.swift Outdated Show resolved Hide resolved
Splito/UI/Home/Account/Feedback/FeedbackViewModel.swift Outdated Show resolved Hide resolved
@canopas canopas deleted a comment from coderabbitai bot Jan 6, 2025
Copy link

@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: 4

🧹 Nitpick comments (9)
Splito/UI/Home/Account/Feedback/MultiMediaSelectionPickerView.swift (3)

13-24: Add documentation for public interface.

Consider adding documentation comments for the public struct and its properties to improve API clarity. This is especially important for public interfaces.

+/// A SwiftUI view that presents a media picker interface for selecting multiple images and videos.
 public struct MultiMediaSelectionPickerView: UIViewControllerRepresentable {
 
+    /// Binding to control the presentation state of the picker
     @Binding var isPresented: Bool
 
+    /// Maximum number of items that can be selected
     let attachmentLimit: Int
+    /// Closure called with selected attachments when picker is dismissed
     let onDismiss: ([Attachment]) -> Void

26-33: Enhance picker configuration options.

The current configuration is basic. Consider adding support for:

  1. Configurable media types (photos only, videos only, or both)
  2. Quality preferences
  3. Customizable appearance beyond just tintColor
 public func makeUIViewController(context: Context) -> PHPickerViewController {
     var configuration = PHPickerConfiguration()
     configuration.selectionLimit = attachmentLimit
+    configuration.filter = .any(of: [.images, .videos])
+    configuration.preferredAssetRepresentationMode = .current
     let picker = PHPickerViewController(configuration: configuration)
     picker.delegate = context.coordinator
     picker.view.tintColor = UIColor(infoColor)
     return picker
 }

94-98: Consider adding progress indication for large media processing.

When processing multiple or large media files, users should see a loading indicator.

 dispatchGroup.notify(queue: .main) {
+    // Assuming you add a loading state binding
+    self.isLoading = false
     self.isPresented = false
     self.onDismiss(attachments)
 }
Splito/UI/Home/Account/Feedback/FeedbackViewModel.swift (3)

14-16: Consider moving size limits to configuration

The character and size limits are hardcoded. Consider moving these to a configuration file or environment variables for easier maintenance and potential runtime configuration.

-    private let TITLE_CHARACTER_MIN_LIMIT = 3
-    private let VIDEO_SIZE_LIMIT_IN_BYTES = 5000000 // 5 MB
-    private let IMAGE_SIZE_LIMIT_IN_BYTES = 3000000 // 3 MB
+    private var TITLE_CHARACTER_MIN_LIMIT: Int { AppConfig.shared.feedbackTitleMinLength }
+    private var VIDEO_SIZE_LIMIT_IN_BYTES: Int { AppConfig.shared.maxVideoSizeInBytes }
+    private var IMAGE_SIZE_LIMIT_IN_BYTES: Int { AppConfig.shared.maxImageSizeInBytes }

24-27: Consider consolidating attachment tracking

Multiple arrays are used to track different attachment states. Consider using a single array of attachments with an enum state property for better state management.

+    enum AttachmentState {
+        case uploading, failed, uploaded
+    }
+
+    struct TrackedAttachment {
+        let attachment: Attachment
+        var state: AttachmentState
+        var url: String?
+    }
+
-    @Published var failedAttachments: [Attachment] = []
-    @Published var attachmentsUrls: [(id: String, url: String)] = []
-    @Published var selectedAttachments: [Attachment] = []
-    @Published var uploadingAttachments: [Attachment] = []
+    @Published private(set) var attachments: [TrackedAttachment] = []

57-59: Extract device info collection to a utility

Device information collection is mixed with feedback creation. Consider extracting this to a separate utility class for better separation of concerns and reusability.

+    private func getDeviceInfo() -> (appVersion: String, deviceName: String, osVersion: String) {
+        return (
+            DeviceInfo.appVersionName,
+            UIDevice.current.name,
+            UIDevice.current.systemVersion
+        )
+    }
+
     let feedback = Feedback(title: title, description: description, userId: userId,
-                            attachmentUrls: attachmentsUrls.map { $0.url }, appVersion: DeviceInfo.appVersionName,
-                            deviceName: UIDevice.current.name, deviceOsVersion: UIDevice.current.systemVersion)
+                            attachmentUrls: attachmentsUrls.map { $0.url },
+                            appVersion: deviceInfo.appVersion,
+                            deviceName: deviceInfo.deviceName,
+                            deviceOsVersion: deviceInfo.osVersion)
functions/src/feedback/feedback_service.ts (1)

41-46: Avoid hard-coding recipient email addresses.
Relying on a hard-coded recipient array can cause maintenance issues and hamper flexibility in different environments. Instead, store recipient addresses in configuration or environment variables.

-    await this.mailService.sendEmail(
-      ["[email protected]"],
-      "[email protected]",
-      "Splito: Feedback Request Created",
-      body,
-    );
+    const toAddresses = process.env.FEEDBACK_RECIPIENTS?.split(",") || ["[email protected]"];
+    await this.mailService.sendEmail(
+      toAddresses,
+      "[email protected]",
+      "Splito: Feedback Request Created",
+      body,
+    );
functions/src/mail/mail_service.ts (1)

23-47: Consider adding inline logging or error handling.
When you create and send the email command, consider adding logs or capturing exceptions locally in case AWS SES returns detailed error messages. This could help diagnose failures more effectively.

async sendEmail(to: string[], from: string, subject: string, body: string): Promise<void> {
  const mail = this.createSendEmailCommand(to, from, subject, body);
  try {
+    console.info(`Sending email to: ${to.join(", ")} with subject '${subject}'`);
    await sesClient.send(mail);
+    console.info(`Email sent successfully to: ${to.join(", ")}`);
  } catch (error) {
+    console.error(`Failed to send email to: ${to.join(", ")}`, error);
    throw error;
  }
}
functions/src/index.ts (1)

30-46: Validate feedback data structure.
Before calling onFeedbackCreated, consider verifying that essential fields (such as created_at or attachment_urls) exist or meet certain criteria (e.g., maximum attachment count). This helps protect against partially formed or malformed documents in the "feedbacks" collection.

  const data = snapshot.data();

+ if (!data || typeof data !== 'object') {
+   logger.error("Feedback data is missing or improperly structured");
+   return;
+ }
  try {
    await feedbackService.onFeedbackCreated(data);
  } catch (error) {
    logger.error('Error handling feedback:', error);
  }
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between e3c11e0 and e4536bf.

📒 Files selected for processing (8)
  • BaseStyle/BaseStyle/Resource/AppColors.swift (1 hunks)
  • BaseStyle/BaseStyle/Resource/BaseAssets.xcassets/Colors/SecondaryLightTextColor.colorset/Contents.json (1 hunks)
  • Splito/UI/Home/Account/Feedback/FeedbackView.swift (1 hunks)
  • Splito/UI/Home/Account/Feedback/FeedbackViewModel.swift (1 hunks)
  • Splito/UI/Home/Account/Feedback/MultiMediaSelectionPickerView.swift (1 hunks)
  • functions/src/feedback/feedback_service.ts (1 hunks)
  • functions/src/index.ts (2 hunks)
  • functions/src/mail/mail_service.ts (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • BaseStyle/BaseStyle/Resource/BaseAssets.xcassets/Colors/SecondaryLightTextColor.colorset/Contents.json
🚧 Files skipped from review as they are similar to previous changes (1)
  • Splito/UI/Home/Account/Feedback/FeedbackView.swift
🔇 Additional comments (8)
BaseStyle/BaseStyle/Resource/AppColors.swift (1)

36-36: Ensure color accessibility standards are addressed.

Adding a new color constant is useful; however, please confirm it meets accessibility requirements, including contrast ratios in both light and dark modes.

Would you like me to run a color contrast check against typical foreground/background usage scenarios in your codebase?

Splito/UI/Home/Account/Feedback/MultiMediaSelectionPickerView.swift (3)

8-11: LGTM! All necessary imports are present.


58-59: Avoid synchronous image loading.

Using synchronous loading can cause UI freezes, especially with large images.


67-75: Enhance error handling and user feedback.

Currently, errors are only logged without user feedback.

Splito/UI/Home/Account/Feedback/FeedbackViewModel.swift (1)

186-205: 🛠️ Refactor suggestion

Add retry mechanism with exponential backoff

The upload functionality should include a retry mechanism with exponential backoff for better reliability in poor network conditions.

+    private let MAX_RETRIES = 3
+    private func uploadWithRetry(data: Data, attachment: Attachment, type: StorageManager.AttachmentType, retryCount: Int = 0) {
+        guard retryCount < MAX_RETRIES else {
+            failedAttachments.append(attachment)
+            uploadingAttachments.removeAll { $0.id == attachment.id }
+            LogE("FeedbackViewModel: Max retries exceeded for attachment: \(attachment.id)")
+            return
+        }
+
+        let delay = TimeInterval(pow(2.0, Double(retryCount)))
+        
+        Task { [weak self] in
+            do {
+                try await Task.sleep(nanoseconds: UInt64(delay * 1_000_000_000))
+                try await self?.uploadAttachment(data: data, attachment: attachment, type: type)
+            } catch {
+                self?.uploadWithRetry(data: data, attachment: attachment, type: type, retryCount: retryCount + 1)
+            }
+        }
+    }

Likely invalid or redundant comment.

functions/src/feedback/feedback_service.ts (1)

5-6: Ensure consistent naming conventions and method responsibilities.
While the class name and method name are expressive, consider clarifying in doc comments whether FeedbackService might handle more feedback-related operations in the future.

functions/src/mail/mail_service.ts (1)

10-11: Ensure environment variables are configured securely.
The code throws an error if credentials are missing, which is good. Confirm that your deployment process securely sets aws.access_key_id and aws.secret_access_key in the Firebase Functions config and that these configs won’t be accidentally exposed in logs or other outputs.

functions/src/index.ts (1)

6-8: Confirm region setup consistency.
Here, the GCP region is set to "asia-south1", while AWS uses "ap-south-1". Confirm that the region mismatch is intentional. Using separate regions for GCP and AWS is valid but ensure you’re aware of any latency or compliance implications.

@cp-nirali-s cp-nirali-s force-pushed the add-send-feedback-option branch from e4536bf to e064228 Compare January 6, 2025 11:26
Copy link

@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: 6

🧹 Nitpick comments (13)
Splito/UI/Home/Account/Feedback/MultiMediaSelectionPickerView.swift (4)

26-33: Consider adding media type filters to the configuration.

The current configuration only sets the selection limit. Consider adding media type filters to restrict selection to specific types:

 var configuration = PHPickerConfiguration()
 configuration.selectionLimit = attachmentLimit
+configuration.filter = PHPickerFilter.any(of: [.images, .videos])
+configuration.preferredAssetRepresentationMode = .current

35-37: Document the empty updateUIViewController method.

Add a documentation comment explaining why no updates are needed:

 public func updateUIViewController(_ uiViewController: PHPickerViewController, context: Context) {
-    // Nothing to update here
+    // This method is required by UIViewControllerRepresentable but not needed
+    // as PHPickerViewController is presented modally and doesn't need updates
 }

49-51: Consider caching and memory management for PHImageManager.

The current implementation could benefit from image caching and memory management settings:

 let imageManager = PHImageManager.default()
 let imageRequestOptions = PHImageRequestOptions()
+imageRequestOptions.deliveryMode = .opportunistic
+imageRequestOptions.isNetworkAccessAllowed = true
+imageRequestOptions.version = .current

95-99: Consider weak self in dispatch group notification.

To prevent potential retain cycles, use [weak self] in the closure:

-dispatchGroup.notify(queue: .main) {
+dispatchGroup.notify(queue: .main) { [weak self] in
-    self.isPresented = false
-    self.onDismiss(attachments)
+    guard let self = self else { return }
+    self.isPresented = false
+    self.onDismiss(attachments)
 }
Splito/UI/Home/Account/Feedback/FeedbackViewModel.swift (3)

13-16: Follow Swift naming conventions for constants

Constants should be static and use camelCase naming convention.

-    let MAX_ATTACHMENTS = 5
-    private let TITLE_CHARACTER_MIN_LIMIT = 3
-    private let VIDEO_SIZE_LIMIT_IN_BYTES = 5000000 // 5 MB
-    private let IMAGE_SIZE_LIMIT_IN_BYTES = 3000000 // 3 MB
+    static let maxAttachments = 5
+    private static let titleCharacterMinLimit = 3
+    private static let videoSizeLimitInBytes = 5_000_000 // 5 MB
+    private static let imageSizeLimitInBytes = 3_000_000 // 3 MB

51-75: Add validation for empty description

The onSubmitBtnTap method validates the title but not the description. Consider adding validation for empty description to ensure meaningful feedback.

     func onSubmitBtnTap() {
-        guard let userId = preference.user?.id, isValidTitle else {
+        guard let userId = preference.user?.id,
+              isValidTitle,
+              !description.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty else {
             shouldShowValidationMessage = !isValidTitle
+            handleError(message: "Please provide a description for your feedback.")
             return
         }

199-206: Localize error messages

Error messages are hardcoded strings. Consider using localized strings for better internationalization support.

     func handleError(message: String? = nil) {
         if let message {
-            showToastFor(toast: ToastPrompt(type: .error, title: "Error", message: message))
+            showToastFor(toast: ToastPrompt(
+                type: .error,
+                title: NSLocalizedString("error.title", comment: "Error alert title"),
+                message: message))
         } else {
             showLoader = false
             showToastForError()
         }
     }
Data/Data/Utils/DeviceInfo.swift (3)

10-10: Add documentation for the DeviceInfo class.

Consider adding documentation comments to describe the purpose and usage of this utility class. This will help other developers understand when and how to use these device information utilities.

+/// A utility class that provides access to device-specific information such as device name, OS version, and app version.
 public class DeviceInfo {

16-18: Add documentation for deviceOsVersion property.

Add documentation to explain the property's purpose and return value format.

+/// Returns the operating system version (e.g., "16.2").
+/// - Returns: The current iOS version string.
 public static var deviceOsVersion: String {

20-22: Enhance version information and add documentation.

Consider including the build number along with the version string for better debugging capabilities. Also, add documentation to explain the property's purpose.

+/// Returns the application's version string from Info.plist.
+/// - Returns: The application's version (e.g., "1.0.0") or empty string if not found.
 public static var appVersionName: String {
-    return Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String ?? ""
+    let version = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String ?? ""
+    let build = Bundle.main.infoDictionary?["CFBundleVersion"] as? String ?? ""
+    return "\(version) (\(build))"
 }
functions/src/index.ts (1)

23-25: Consider enhancing service initialization.

While the service initialization order is correct, consider these improvements:

  1. Move the REGION constant to a configuration file for better maintainability
  2. Add error handling for service initialization

Example improvement:

+ import { config } from './config';
- const REGION = "asia-south1";
+ const { REGION } = config;

- const mailService = new MailService();
- const feedbackService = new FeedbackService(mailService);
+ let mailService: MailService;
+ let feedbackService: FeedbackService;
+ try {
+   mailService = new MailService();
+   feedbackService = new FeedbackService(mailService);
+   logger.info('Services initialized successfully');
+ } catch (error) {
+   logger.error('Failed to initialize services:', error);
+   throw error;
+ }
Data/Data/Helper/Firebase/StorageManager.swift (2)

Line range hint 17-33: Consider renaming ImageStoreType to better reflect its purpose

The enum now handles various attachment types, not just images. Consider renaming it to StorageType or AttachmentStoreType for better clarity.

-public enum ImageStoreType {
+public enum StorageType {

Line range hint 78-87: Update logging messages and add URL validation

The logging messages still reference "image" instead of "attachment". Also, consider adding URL validation.

 public func deleteAttachment(attachmentUrl: String) async throws {
+    guard URL(string: attachmentUrl)?.scheme == "https" else {
+        throw StorageError.invalidUrl
+    }
     do {
         let storageRef = storage.reference(forURL: attachmentUrl)
         try await storageRef.delete()
-        LogD("StorageManager: \(#function) Image deleted successfully.")
+        LogD("StorageManager: \(#function) Attachment deleted successfully.")
     } catch {
-        LogE("StorageManager: \(#function) Failed to delete image: \(error).")
+        LogE("StorageManager: \(#function) Failed to delete attachment: \(error).")
         throw error
     }
 }
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between e4536bf and e064228.

📒 Files selected for processing (10)
  • BaseStyle/BaseStyle/Resource/AppColors.swift (1 hunks)
  • BaseStyle/BaseStyle/Resource/BaseAssets.xcassets/Colors/SecondaryLightTextColor.colorset/Contents.json (1 hunks)
  • Data/Data/Helper/Firebase/StorageManager.swift (2 hunks)
  • Data/Data/Utils/DeviceInfo.swift (1 hunks)
  • Splito/UI/Home/Account/Feedback/FeedbackView.swift (1 hunks)
  • Splito/UI/Home/Account/Feedback/FeedbackViewModel.swift (1 hunks)
  • Splito/UI/Home/Account/Feedback/MultiMediaSelectionPickerView.swift (1 hunks)
  • functions/src/feedback/feedback_service.ts (1 hunks)
  • functions/src/index.ts (2 hunks)
  • functions/src/mail/mail_service.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (5)
  • BaseStyle/BaseStyle/Resource/AppColors.swift
  • BaseStyle/BaseStyle/Resource/BaseAssets.xcassets/Colors/SecondaryLightTextColor.colorset/Contents.json
  • functions/src/feedback/feedback_service.ts
  • functions/src/mail/mail_service.ts
  • Splito/UI/Home/Account/Feedback/FeedbackView.swift
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: build
🔇 Additional comments (10)
Splito/UI/Home/Account/Feedback/MultiMediaSelectionPickerView.swift (4)

1-12: LGTM! File structure and imports are well-organized.

The file includes all necessary imports and follows proper Swift conventions.


13-24: LGTM! Well-structured view declaration and initialization.

The public API is clean, properties are well-named, and the initialization follows SwiftUI best practices.


67-75: Previous comment about error handling is still applicable.

The error handling needs improvement to provide better user feedback.


77-92: Previous comment about video handling and memory management is still applicable.

The implementation needs video size limits and proper cleanup.

Splito/UI/Home/Account/Feedback/FeedbackViewModel.swift (1)

210-212: LGTM!

The FocusedField enum is well-defined and serves its purpose.

Data/Data/Utils/DeviceInfo.swift (2)

10-23: Add unit tests for DeviceInfo class.

Since this class is used for collecting support information, it's crucial to ensure it works correctly across different scenarios. Consider adding unit tests to verify:

  • Proper version string parsing
  • Handling of missing Info.plist values
  • Format of the combined version and build number

Would you like me to help create a test suite for this class?


12-14: Consider privacy implications of device name.

The device name often contains personal information (e.g., "John's iPhone"). Consider if this is necessary for your use case or if a more privacy-preserving alternative would suffice.

Also, add documentation to explain the property's purpose and potential privacy implications:

+/// Returns the device name. Note: This may contain personal information set by the user.
+/// - Returns: The current device name as set in system settings.
 public static var deviceName: String {
✅ Verification successful

Device name usage is appropriate for feedback diagnostics

The device name is only collected during user-initiated feedback submission, along with other diagnostic information like app version and OS version. This is a standard practice for support purposes and is covered by the app's privacy policy. The implementation is appropriate as-is.

🏁 Scripts executed

The following scripts were executed for the analysis:

Error: No shell scripts found


Script:

#!/bin/bash
# Search for usages of deviceName
echo "=== Searching for deviceName usages ==="
rg "deviceName" -B 2 -A 2

echo -e "\n=== Searching for privacy-related documentation ==="
rg -i "privacy|gdpr|personal.?data" -g "*.{md,swift}"

echo -e "\n=== Looking for alternative device identifiers ==="
rg "identifier|UUID|UDID|deviceId" -g "*.swift" -B 2 -A 2

Length of output: 11307

functions/src/index.ts (2)

4-8: LGTM! Import statements are well-organized.

The imports are properly structured and follow a consistent pattern, with clear separation between Firebase core imports and custom service imports.


30-32: Verify feedback document path structure.

The feedback observer is correctly configured, but let's verify the document path structure in the codebase.

✅ Verification successful

Feedback document path structure is correctly implemented

The document path "feedbacks/{feedbackId}" is consistently used throughout the codebase, and there are no conflicting patterns or variations. The FeedbackService handles only the email notifications without direct Firestore operations, maintaining a clean separation of concerns.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for references to the feedback collection to ensure consistent path usage
rg -g '!node_modules' -g '*.{ts,js}' -i 'feedbacks/[^/]+' --context 2

Length of output: 356


Script:

#!/bin/bash
# Search for other variations of feedback collection references and related types
echo "=== Searching for feedback collection references ==="
rg -g '!node_modules' -g '*.{ts,js}' -i 'feedback/' --context 2

echo -e "\n=== Searching for feedbackId references ==="
rg -g '!node_modules' -g '*.{ts,js}' 'feedbackId' --context 2

echo -e "\n=== Searching for Feedback type definitions ==="
ast-grep --pattern 'interface Feedback {
  $$$
}'

Length of output: 1214


Script:

#!/bin/bash
# Check feedback service implementation
echo "=== Checking feedback service implementation ==="
cat functions/src/feedback/feedback_service.ts 2>/dev/null || echo "File not found"

echo -e "\n=== Searching for feedback collection path constants ==="
rg -g '!node_modules' -g '*.{ts,js}' -i 'const.*feedback.*collection' --context 2

Length of output: 1765

Data/Data/Helper/Firebase/StorageManager.swift (1)

Line range hint 1-87: Verify existing image handling functionality

The refactoring from image-specific to general attachment handling is significant. Please ensure all existing image upload/update flows continue to work correctly.

Run the following script to find all existing image upload/update usages that might be affected:

✅ Verification successful

Refactoring is already properly implemented

All repositories are already using the new generalized attachment API with proper ImageStoreType cases:

  • UserRepository: .user
  • GroupRepository: .group
  • TransactionRepository: .payment
  • ExpenseRepository: .expense
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Find all references to the old image methods
rg -l "uploadImage|updateImage|deleteImage" --type swift

# Find all usages of ImageStoreType to verify they're updated
rg "ImageStoreType\." --type swift -A 2

Length of output: 377


Script:

#!/bin/bash
# Check actual usage in repositories
echo "=== UserRepository.swift ==="
rg "StorageManager" Data/Data/Repository/UserRepository.swift -B 2 -A 5

echo -e "\n=== GroupRepository.swift ==="
rg "StorageManager" Data/Data/Repository/GroupRepository.swift -B 2 -A 5

echo -e "\n=== TransactionRepository.swift ==="
rg "StorageManager" Data/Data/Repository/TransactionRepository.swift -B 2 -A 5

echo -e "\n=== ExpenseRepository.swift ==="
rg "StorageManager" Data/Data/Repository/ExpenseRepository.swift -B 2 -A 5

echo -e "\n=== ImagePickerView.swift ==="
rg "StorageManager" BaseStyle/BaseStyle/CustomUI/ImagePickerView.swift -B 2 -A 5

Length of output: 2464


Script:

#!/bin/bash
# Check for actual storage method calls in repositories
echo "=== UserRepository Storage Calls ==="
rg "storageManager\." Data/Data/Repository/UserRepository.swift -B 1 -A 3

echo -e "\n=== GroupRepository Storage Calls ==="
rg "storageManager\." Data/Data/Repository/GroupRepository.swift -B 1 -A 3

echo -e "\n=== TransactionRepository Storage Calls ==="
rg "storageManager\." Data/Data/Repository/TransactionRepository.swift -B 1 -A 3

echo -e "\n=== ExpenseRepository Storage Calls ==="
rg "storageManager\." Data/Data/Repository/ExpenseRepository.swift -B 1 -A 3

Length of output: 3149

@canopas canopas deleted a comment from coderabbitai bot Jan 6, 2025
Copy link

@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 (3)
Splito/UI/Home/Account/Feedback/FeedbackViewModel.swift (3)

13-16: Move constants to a configuration namespace

Consider organizing the constants in a nested Configuration enum for better maintainability.

-    let MAX_ATTACHMENTS = 5
-    private let TITLE_CHARACTER_MIN_LIMIT = 3
-    private let VIDEO_SIZE_LIMIT_IN_BYTES = 5000000 // 5 MB
-    private let IMAGE_SIZE_LIMIT_IN_BYTES = 3000000 // 3 MB
+    private enum Configuration {
+        static let maxAttachments = 5
+        static let titleCharacterMinLimit = 3
+        static let videoSizeLimitInBytes = 5_000_000 // 5 MB
+        static let imageSizeLimitInBytes = 3_000_000 // 3 MB
+    }

86-88: Use Configuration constant instead of direct MAX_ATTACHMENTS access

Replace the direct access to MAX_ATTACHMENTS with the Configuration constant.

-        if attachmentsUrls.count >= MAX_ATTACHMENTS {
-            handleError(message: "Maximum \(MAX_ATTACHMENTS) attachments allowed.")
+        if attachmentsUrls.count >= Configuration.maxAttachments {
+            handleError(message: "Maximum \(Configuration.maxAttachments) attachments allowed.")

127-129: Document empty case handling

Add a comment explaining why these cases are empty.

         case .camera, .remove:
+            // These cases are handled by the view layer
             break
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between e064228 and 13e866a.

📒 Files selected for processing (1)
  • Splito/UI/Home/Account/Feedback/FeedbackViewModel.swift (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: build
🔇 Additional comments (4)
Splito/UI/Home/Account/Feedback/FeedbackViewModel.swift (4)

41-46: ⚠️ Potential issue

Make router reference weak to prevent retain cycles

The router is stored as a strong reference which could create a retain cycle.

-    private let router: Router<AppRoute>
+    private weak var router: Router<AppRoute>?

     init(router: Router<AppRoute>) {
         self.router = router
         super.init()
     }

Likely invalid or redundant comment.


67-69: ⚠️ Potential issue

Fix potential retain cycle in alert closure

The closure capturing self could create a retain cycle.

     self.alert = .init(message: "Thanks! your feedback has been recorded.",
                       positiveBtnTitle: "Ok",
-                      positiveBtnAction: { [weak self] in self?.router.pop() })
+                      positiveBtnAction: { [weak self] in
+                          guard let self = self else { return }
+                          self.router?.pop()
+                      })

Likely invalid or redundant comment.


200-207: 🛠️ Refactor suggestion

Improve error handling with specific error types and localization

The current error handling is too generic. Consider implementing specific error types and localized messages.

+    enum FeedbackError: LocalizedError {
+        case attachmentSizeExceeded(type: String, limit: Int)
+        case uploadFailed(reason: String)
+        case deletionFailed(reason: String)
+        
+        var errorDescription: String? {
+            switch self {
+            case .attachmentSizeExceeded(let type, let limit):
+                return String(format: NSLocalizedString("error_attachment_size_exceeded_%@_%d", comment: ""), type, limit)
+            case .uploadFailed(let reason):
+                return String(format: NSLocalizedString("error_upload_failed_%@", comment: ""), reason)
+            case .deletionFailed(let reason):
+                return String(format: NSLocalizedString("error_deletion_failed_%@", comment: ""), reason)
+            }
+        }
+    }

     func handleError(message: String? = nil) {
-        if let message {
-            showToastFor(toast: ToastPrompt(type: .error, title: "Error", message: message))
+        if let error = message as? FeedbackError {
+            showToastFor(toast: ToastPrompt(type: .error, 
+                title: NSLocalizedString("error", comment: ""), 
+                message: error.localizedDescription))
         } else {
             showLoader = false
             showToastForError()
         }
     }

Likely invalid or redundant comment.


171-197: ⚠️ Potential issue

Add file type validation and task cancellation

The attachment upload needs file type validation and proper task cancellation support.

+    private let SUPPORTED_IMAGE_TYPES = ["image/jpeg", "image/png"]
+    private let SUPPORTED_VIDEO_TYPES = ["video/mp4", "video/quicktime"]
+    private var attachmentTasks: [String: Task<Void, Never>] = [:]

     private func uploadAttachment(data: Data, attachment: Attachment, maxSize: Int, type: StorageManager.AttachmentType) {
+        guard let mimeType = attachment.mimeType else {
+            handleError(message: "Unsupported file format")
+            return
+        }
+
+        switch type {
+        case .image:
+            guard SUPPORTED_IMAGE_TYPES.contains(mimeType) else {
+                handleError(message: "Unsupported image format. Please use JPEG or PNG.")
+                return
+            }
+        case .video:
+            guard SUPPORTED_VIDEO_TYPES.contains(mimeType) else {
+                handleError(message: "Unsupported video format. Please use MP4 or MOV.")
+                return
+            }
+        }

         if data.count <= maxSize {
             uploadingAttachments.append(attachment)

-            Task { [weak self] in
+            let task = Task { [weak self] in
                 do {
                     let attachmentId = attachment.id
                     let attachmentUrl = try await self?.feedbackRepository.uploadAttachment(attachmentId: attachmentId,
                                                                                         attachmentData: data, attachmentType: type)
                     if let attachmentUrl {
                         self?.attachmentsUrls.append((id: attachmentId, url: attachmentUrl))
                         self?.uploadingAttachments.removeAll { $0.id == attachmentId }
                     }
                     LogD("FeedbackViewModel: \(#function) Attachment uploaded successfully.")
                 } catch {
                     self?.failedAttachments.append(attachment)
                     self?.uploadingAttachments.removeAll { $0.id == attachment.id }
                     LogE("FeedbackViewModel: \(#function) Failed to upload attachment: \(error)")
                 }
             }
+            attachmentTasks[attachment.id] = task
         }
     }

+    deinit {
+        attachmentTasks.values.forEach { $0.cancel() }
+    }

Likely invalid or redundant comment.

Copy link

@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 comments (1)
BaseStyle/BaseStyle.xcodeproj/project.pbxproj (1)

Tests needed for new UI components

The test target exists but lacks test coverage for the new MultiMediaSelectionPickerView and MediaPickerOptionsView components. The BaseStyleTests.swift file only contains template code with no actual test implementations.

  • Add tests for MultiMediaSelectionPickerView:
    • Media selection state management
    • Multiple selection behavior
    • Selection limits and validation
  • Add tests for MediaPickerOptionsView:
    • Options presentation
    • Option selection handling
    • View state updates
🔗 Analysis chain

Line range hint 10-527: Consider adding tests for the new components.

While the project structure changes are correct, ensure that appropriate test coverage is added for the new MultiMediaSelectionPickerView and MediaPickerOptionsView components.

Run this script to check for test coverage:

Consider adding test cases for:

  • Media selection functionality
  • Multiple media handling
  • Error cases and edge conditions
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for test coverage of the new components

# Search for test files related to the new components
echo "Searching for test files..."
fd -e swift -e xctestplan "test.*MediaPicker|MediaPicker.*test" 

# Search for test cases within existing test files
echo "Searching for test cases in existing files..."
rg -l "test.*MediaPicker|func test.*media|func test.*picker" --type swift

Length of output: 307


Script:

#!/bin/bash
# First, find all test-related files to understand the testing structure
echo "=== Searching for all test files ==="
fd -e swift ".*Tests?\.swift$"

echo -e "\n=== Searching for test target configuration ==="
fd ".*\.xctest"

echo -e "\n=== Checking for test directories ==="
fd -t d ".*[Tt]est.*"

echo -e "\n=== Searching for test-related strings in project file ==="
rg "Test" "BaseStyle/BaseStyle.xcodeproj/project.pbxproj"

Length of output: 3827


Script:

#!/bin/bash
# Check content of BaseStyleTests.swift
echo "=== Content of BaseStyleTests.swift ==="
cat "BaseStyle/BaseStyleTests/BaseStyleTests.swift"

# Look for any existing view-related tests
echo -e "\n=== Searching for view-related tests ==="
rg "class.*Test|func test.*View" "BaseStyle/BaseStyleTests/BaseStyleTests.swift"

Length of output: 1590

🧹 Nitpick comments (9)
BaseStyle/BaseStyle/CustomUI/MultiMediaSelectionPickerView.swift (8)

13-14: Consider exposing comment documentation for clarity.

Documenting how isPresented is used to control picker visibility can help future maintainers quickly understand the binding’s purpose.


24-31: Initialize PHPickerConfiguration with desired filter(s).

If you intend to allow only images and videos, consider specifying configuration.filter = .any(of: [.images, .videos]) to reduce undesired asset types.

 var configuration = PHPickerConfiguration()
+configuration.filter = .any(of: [.images, .videos])
 configuration.selectionLimit = attachmentLimit
 let picker = PHPickerViewController(configuration: configuration)

37-41: Leverage Swift concurrency for clarity.

Using DispatchGroup works fine, but adopting Swift’s structured concurrency (e.g., async/await) might improve readability and reduce potential race conditions.


50-53: Initialize PHImageRequestOptions earlier or pass as parameter.

Currently, imageRequestOptions is modified in didFinishPicking (line 56). Consider making it a constant property or passing it in to avoid potential side effects if extended in the future.


64-73: Handle large image memory usage gracefully.

If users select very large images, resizing and memory usage can become a bottleneck. You might consider adding asynchronous scaling or progressive decoding for more robust memory management.


75-90: Ensure robust video file error handling.

Currently, an error is printed but not returned to the user. For better UX, consider prompting the user if a video fails to load.


81-81: Check for file removal errors.

try? FileManager.default.removeItem(at: url) silently ignores potential errors. Consider logging or handling these more explicitly, especially if failure to remove temp files leads to disk usage growth.


93-96: Prompt user after finishing selection.

Currently, the code dismisses the picker once all attachments load. If you'd like a user confirmation step (e.g., “Are you sure?”), that can happen before closing. This ensures the user is fully aware of the attachments being added.

Splito.xcodeproj/project.pbxproj (1)

663-663: Check references to 'Feedback' under 'Account' folder.

Ensure that referencing the new group under “Account” is an intentional design choice and doesn't conflict with future expansions (e.g., Feedback might also be used in other modules).

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 13e866a and 9ebe0fe.

📒 Files selected for processing (5)
  • BaseStyle/BaseStyle.xcodeproj/project.pbxproj (4 hunks)
  • BaseStyle/BaseStyle/CustomUI/MultiMediaSelectionPickerView.swift (1 hunks)
  • Data/Data/Model/Feedback.swift (1 hunks)
  • Splito.xcodeproj/project.pbxproj (5 hunks)
  • functions/src/feedback/feedback_service.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • Data/Data/Model/Feedback.swift
  • functions/src/feedback/feedback_service.ts
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: build
🔇 Additional comments (11)
BaseStyle/BaseStyle.xcodeproj/project.pbxproj (2)

310-311: LGTM! New UI components are properly organized.

The new media picker components are correctly placed in the CustomUI group, maintaining the project's organizational structure.


10-10: Verify the impact of file changes on existing functionality.

The changes look good from a project structure perspective. However, since MailComposeView.swift has been removed (as mentioned in the summary) and replaced with new media picker components, we should ensure:

  1. All previous email composition functionality has been properly migrated
  2. Any existing features that depended on MailComposeView have been updated

Run this script to check for any remaining references to the removed functionality:

Also applies to: 13-13, 73-73, 76-76, 521-521, 527-527

✅ Verification successful

Clean removal confirmed - no remaining dependencies found

The verification shows that MailComposeView and related email composition functionality have been completely removed from the project. All found mail-related references are for different features (authentication, user management) and not related to the removed email composition functionality. The addition of MultiMediaSelectionPickerView appears to be a clean replacement with no conflicting dependencies.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for any remaining references to MailComposeView that might need updating

# Search for references to the removed MailComposeView
echo "Searching for references to MailComposeView..."
rg -l "MailComposeView"

# Search for any email-related functionality that might need migration
echo "Searching for email-related functionality..."
rg -l "MFMailComposeViewController|canSendMail|mailComposeDelegate"

Length of output: 295


Script:

#!/bin/bash
# Case-insensitive search for mail-related terms
echo "Searching for mail-related terms (case-insensitive)..."
rg -il "mail|compose|mailcompose|mailcomposeview"

# Check specifically in the project file for the removed MailComposeView
echo "Checking project file for MailComposeView references..."
rg "MailComposeView" BaseStyle/BaseStyle.xcodeproj/project.pbxproj

# Search for any import statements related to mail functionality
echo "Searching for mail-related imports..."
ast-grep --pattern 'import $_Mail$_'

Length of output: 1512

BaseStyle/BaseStyle/CustomUI/MultiMediaSelectionPickerView.swift (4)

11-12: Great use of UIViewControllerRepresentable.

By conforming to UIViewControllerRepresentable, this struct seamlessly bridges SwiftUI and UIKit's PHPickerViewController, ensuring minimal boilerplate. This approach is clean and follows Apple's recommended patterns.


18-22: Validate the attachmentLimit.

When attachmentLimit is set to a very large number or zero, confirm that the UI and data processing can handle edge cases without crashing or leading to memory issues.

Would you like a script to probe how attachmentLimit is used throughout the code?


29-29: Handle potential fallback for tint color.

UIColor(infoColor) suggests a custom color, but consider a fallback color if infoColor is missing or doesn't exist in certain contexts.


102-116: Good design of the Attachment struct.

Providing distinct fields for image, videoData, and video plus an identifying name is concise and flexible. Nice job making it public and reusable.

Splito.xcodeproj/project.pbxproj (5)

20-21: New feedback-related files are properly added to the build.

The references to “FeedbackView.swift" and “FeedbackViewModel.swift" in sources ensure these files are compiled. No issues spotted here.


167-168: File references for feedback files appear consistent.

These references match the newly added Swift files. Confirm that the filenames match exactly to avoid broken references.


347-355: Great addition of a 'Feedback' group for project organization.

Creating a dedicated group keeps related files together, enhancing maintainability.


1114-1114: FeedbackViewModel added to the build phase.

Ensure all necessary frameworks or dependencies (e.g., for uploading attachments) are linked here or in separate build phases as needed.


1119-1119: FeedbackView included in the build phase.

Everything looks consistent. If you have any usage within SwiftUI previews, confirm that Previews can reference it as well.

Copy link

@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 (13)
BaseStyle/BaseStyle/CustomUI/MultiMediaSelectionPickerView.swift (4)

11-22: Ensure consistent access modifiers and documentation.

Since MultiMediaSelectionPickerView is marked public, consider documenting it for future reference and maintaining consistent access control for its properties, ensuring that only the necessary members are exposed.


29-29: Customize tintColor with caution.

While setting a custom tint color can help with brand consistency, ensure that other UI elements remain accessible, especially for users with visual impairments. Consider system dynamic colors or high-contrast palette.


73-88: Check video loading behavior for large files.

Loading video data into memory might lead to memory usage issues. Consider streaming or partial transfer if large video files are expected.


99-114: Add MIME-type checks for attachments.

While the selected attachments are validated by iOS Photos, additional checks for MIME-types or file extensions can guard against unexpected or corrupted files.

Splito/UI/Home/Account/Feedback/FeedbackViewModel.swift (7)

32-34: Remove trailing whitespace to comply with SwiftLint.

The static analysis flagged trailing whitespace. Consider removing them for cleaner diffs and code style compliance.

-    
+    
🧰 Tools
🪛 SwiftLint (0.57.0)

[Warning] 32-32: Lines should not have trailing whitespace

(trailing_whitespace)


[Warning] 34-34: Lines should not have trailing whitespace

(trailing_whitespace)


41-47: Consider a weak reference for router.

Storing router as a strong reference can lead to retain cycles depending on the navigation flow. Evaluate changing this to weak var router: Router<AppRoute>?.

- private let router: Router<AppRoute>
+ private weak var router: Router<AppRoute>?

80-85: Add concurrency safeguards when appending attachments.

Multiple attachments can be processed concurrently by the system or user repetition. Consider using a synchronization mechanism when modifying selectedAttachments.


100-114: Cancel in-progress upload before removing attachment.

If an attachment is being uploaded, consider canceling that upload task first to avoid wasted resources.


150-161: Avoid potential data races on arrays.

Multiple async tasks may modify attachmentsUrls, selectedAttachments, and uploadingAttachments. Accessing these arrays within withAnimation implies the main thread is used, but consider a single, well-defined queue or other concurrency-safe approaches if these lists grow large or are mutated in background threads.


163-171: Implement fallback for unsupported file types.

Currently, the code only checks for image or video data. For better error handling, add a fallback path or error if an attachment is of unknown type.


173-199: Include progress or queued-state to inform users.

Uploads can take time, especially for large files. Consider providing progress status or queued-state to improve user experience.

Splito/UI/Home/Account/Feedback/FeedbackView.swift (2)

131-142: Rename “titleText” to “descriptionText” for clarity
Within FeedbackDescriptionView, the property titleText is used to store the description. Renaming it would prevent confusion in the future.

-struct FeedbackDescriptionView: View {
-    @Binding var titleText: String
+struct FeedbackDescriptionView: View {
+    @Binding var descriptionText: String
     var focusField: FocusState<FeedbackViewModel.FocusedField?>.Binding

     var body: some View {
-        TextEditor(text: $titleText)
+        TextEditor(text: $descriptionText)
         ...

180-188: Consider validating or resizing oversized attachments
Large images or lengthy videos may cause performance and memory issues. Consider pre-checking file size or dimensions, and prompt users or compress the media before upload.

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 9ebe0fe and b665260.

📒 Files selected for processing (9)
  • BaseStyle/BaseStyle/CustomUI/MultiMediaSelectionPickerView.swift (1 hunks)
  • BaseStyle/BaseStyle/Extension/UIImage+Extension.swift (1 hunks)
  • Data/Data/Model/Feedback.swift (1 hunks)
  • Data/Data/Store/FeedbackStore.swift (1 hunks)
  • Splito/Localization/Localizable.xcstrings (8 hunks)
  • Splito/UI/Home/Account/Feedback/FeedbackView.swift (1 hunks)
  • Splito/UI/Home/Account/Feedback/FeedbackViewModel.swift (1 hunks)
  • Splito/UI/Home/Groups/Create Group/CreateGroupView.swift (1 hunks)
  • functions/src/feedback/feedback_service.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (6)
  • Splito/UI/Home/Groups/Create Group/CreateGroupView.swift
  • Data/Data/Store/FeedbackStore.swift
  • Data/Data/Model/Feedback.swift
  • BaseStyle/BaseStyle/Extension/UIImage+Extension.swift
  • Splito/Localization/Localizable.xcstrings
  • functions/src/feedback/feedback_service.ts
🧰 Additional context used
🪛 SwiftLint (0.57.0)
Splito/UI/Home/Account/Feedback/FeedbackViewModel.swift

[Warning] 32-32: Lines should not have trailing whitespace

(trailing_whitespace)


[Warning] 34-34: Lines should not have trailing whitespace

(trailing_whitespace)

⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: build
🔇 Additional comments (4)
BaseStyle/BaseStyle/CustomUI/MultiMediaSelectionPickerView.swift (2)

37-39: Double-check the coordinator’s ownership.

When using UIViewControllerRepresentable, verify that the MultiMediaSelectionPickerCoordinator is not inadvertently retained. SwiftUI usually handles this correctly, but watch for memory leaks if additional strong references exist.


62-72: 🛠️ Refactor suggestion

Potential large image loading overhead.

Images are loaded synchronously (imageRequestOptions.isSynchronous = true). This may block the main thread if images are large. Consider using asynchronous loading or downscaling for performance.

- imageRequestOptions.isSynchronous = true
+ imageRequestOptions.isSynchronous = false

Likely invalid or redundant comment.

Splito/UI/Home/Account/Feedback/FeedbackView.swift (2)

25-27: Title validation logic looks great
The validation and error messaging for the title field is well-structured and user-friendly.


67-73: Wrap the dismissal in a closure to avoid accidental immediate invocation
This appears to be the same issue raised in a past review comment, ensuring the function is invoked only after the user finishes picking.

-sheet(isPresented: $viewModel.showMediaPicker) {
-    MultiMediaSelectionPickerView(
-        isPresented: $viewModel.showMediaPicker,
-        attachmentLimit: abs(viewModel.attachmentsUrls.count - viewModel.MAX_ATTACHMENTS),
-        onDismiss: viewModel.onMediaPickerSheetDismiss(attachments:)
-    )
+sheet(isPresented: $viewModel.showMediaPicker) {
+    MultiMediaSelectionPickerView(
+        isPresented: $viewModel.showMediaPicker,
+        attachmentLimit: abs(viewModel.attachmentsUrls.count - viewModel.MAX_ATTACHMENTS),
+        onDismiss: { pickedAttachments in
+            viewModel.onMediaPickerSheetDismiss(attachments: pickedAttachments)
+        }
+    )
 }

@cp-amisha-i
Copy link
Collaborator Author

cp-amisha-i commented Jan 7, 2025

Let's show success toast on feedback submission.

Copy link

@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: 3

🧹 Nitpick comments (3)
functions/src/index.ts (3)

4-9: Consider organizing imports by type

Group related imports together for better maintainability:

  1. External dependencies (firebase-admin, firebase-functions)
  2. Internal services (users, notifications, feedback, mail)
import * as admin from 'firebase-admin';
import * as logger from 'firebase-functions/logger';
+import { onDocumentCreated } from "firebase-functions/v2/firestore";

import { onGroupWrite } from './users/users_service';
import { onActivityCreate } from './notifications/notifications_service';
import { FeedbackService } from "./feedback/feedback_service";
-import { onDocumentCreated } from "firebase-functions/v2/firestore";
import { MailService } from './mail/mail_service';

24-26: Consider lazy initialization of services

Global service instantiation can increase cold start times. Consider moving service initialization inside the function handler.

-const mailService = new MailService();
-const REGION = "asia-south1";
-const feedbackService = new FeedbackService(mailService);

+const REGION = process.env.REGION || "asia-south1";
+
+function getServices() {
+  const mailService = new MailService();
+  return {
+    feedbackService: new FeedbackService(mailService)
+  };
+}

28-30: Consider migrating all functions to Firebase v2

The codebase mixes v1 (exports.onGroupWrite) and v2 (export const feedbackCreateObserver) function exports. Consider migrating all functions to v2 for consistency and to leverage newer features.

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between b665260 and 1c14bf1.

📒 Files selected for processing (8)
  • Data/Data.xcodeproj/project.pbxproj (9 hunks)
  • Data/Data/Repository/FeedbackRepository.swift (1 hunks)
  • Splito/Localization/Localizable.xcstrings (7 hunks)
  • Splito/UI/Home/Account/Feedback/FeedbackView.swift (1 hunks)
  • Splito/UI/Home/Account/Feedback/FeedbackViewModel.swift (1 hunks)
  • functions/src/feedback/feedback_service.ts (1 hunks)
  • functions/src/index.ts (2 hunks)
  • functions/src/mail/mail_service.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (6)
  • functions/src/feedback/feedback_service.ts
  • Splito/Localization/Localizable.xcstrings
  • functions/src/mail/mail_service.ts
  • Data/Data/Repository/FeedbackRepository.swift
  • Splito/UI/Home/Account/Feedback/FeedbackView.swift
  • Splito/UI/Home/Account/Feedback/FeedbackViewModel.swift
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: build
🔇 Additional comments (2)
Data/Data.xcodeproj/project.pbxproj (2)

14-17: Well-organized file structure following the established architecture pattern.

The new feedback-related files are properly organized following the existing Model-Store-Repository pattern, with clear separation of concerns:

  • Model: Feedback.swift
  • Store: FeedbackStore.swift for data persistence
  • Repository: FeedbackRepository.swift for business logic
  • Utils: DeviceInfo.swift for supporting functionality

Also applies to: 78-81, 191-191, 205-205, 215-215, 262-262


191-192: Consistent architectural approach.

The feedback implementation correctly follows the established architectural patterns in the project:

  1. Clear separation of concerns with Model, Store, and Repository layers
  2. Proper grouping in the project structure
  3. Consistent file naming conventions

Also applies to: 205-206, 215-216, 262-263

Data/Data.xcodeproj/project.pbxproj Show resolved Hide resolved
functions/src/index.ts Show resolved Hide resolved
functions/src/index.ts Show resolved Hide resolved
@cp-nirali-s cp-nirali-s force-pushed the add-send-feedback-option branch 4 times, most recently from d4044df to 7159ca3 Compare January 7, 2025 13:41
@cp-amisha-i cp-amisha-i force-pushed the add-send-feedback-option branch from 7159ca3 to 1c14bf1 Compare January 8, 2025 08:52
@cp-nirali-s cp-nirali-s force-pushed the add-send-feedback-option branch from 1c14bf1 to a0243ce Compare January 8, 2025 11:50
@cp-amisha-i cp-amisha-i force-pushed the add-send-feedback-option branch from a0243ce to 1c14bf1 Compare January 8, 2025 12:02
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (2)
functions/src/mail/mail_service.ts (2)

1-4: Improve code quality configuration

  1. Instead of disabling ESLint globally, specify the rules you want to disable:
-/* eslint-disable */
+/* eslint-disable @typescript-eslint/no-var-requires */
  1. Consider using ES modules import for consistency:
-require('dotenv').config()
+import dotenv from 'dotenv';
+dotenv.config();

6-13: Enhance AWS credentials handling

  1. Move region to environment variables for flexibility across environments
  2. Improve error message to indicate which specific credential is missing
  3. Consider using type-safe environment variables with zod or similar
-const REGION = "ap-south-1";
+const REGION = process.env.AWS_REGION;

 if (!AWS_ACCESS_KEY_ID || !AWS_SECRET_ACCESS_KEY) {
-  throw new Error('AWS credentials are missing');
+  throw new Error(
+    `AWS credentials are missing: ${!AWS_ACCESS_KEY_ID ? 'AWS_ACCESS_KEY_ID' : ''} ${
+      !AWS_SECRET_ACCESS_KEY ? 'AWS_SECRET_ACCESS_KEY' : ''
+    }`.trim()
+  );
 }
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 1c14bf1 and 59f7317.

⛔ Files ignored due to path filters (1)
  • functions/firestore-debug.log is excluded by !**/*.log
📒 Files selected for processing (4)
  • functions/.gitignore (1 hunks)
  • functions/package.json (1 hunks)
  • functions/src/feedback/feedback_service.ts (1 hunks)
  • functions/src/mail/mail_service.ts (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • functions/.gitignore
🚧 Files skipped from review as they are similar to previous changes (2)
  • functions/package.json
  • functions/src/feedback/feedback_service.ts
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: build
🔇 Additional comments (1)
functions/src/mail/mail_service.ts (1)

3-3: Verify AWS SDK version compatibility

Based on the previous comment about deprecated config, let's verify the AWS SDK version compatibility:

✅ Verification successful

AWS SDK implementation is up-to-date and follows best practices

The code uses the latest AWS SDK v3 (^3.721.0) with the recommended modular imports and secure credential management via environment variables.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check package.json for AWS SDK version
echo "Checking AWS SDK version..."
fd package.json | xargs cat | jq '.dependencies["@aws-sdk/client-ses"]'

# Check for any AWS SDK deprecation notices in the codebase
echo "Checking for AWS SDK deprecation comments..."
rg -i "deprecat|aws" --type ts

Length of output: 998

functions/src/mail/mail_service.ts Outdated Show resolved Hide resolved
functions/src/mail/mail_service.ts Outdated Show resolved Hide resolved
Copy link

@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 (1)
BaseStyle/BaseStyle/Resource/BaseAssets.xcassets/Colors/ErrorColor.colorset/Contents.json (1)

15-31: Consider adjusting the dark mode error color intensity

While adding dark mode support is great, the current color (0xFF, 0x61, 0x61) might be too bright for dark environments. Consider using a slightly less intense red component while maintaining error visibility.

       "components" : {
         "alpha" : "1.000",
         "blue" : "0x61",
         "green" : "0x61",
-        "red" : "0xFF"
+        "red" : "0xE6"
       }

This adjustment would reduce eye strain while still maintaining the error state visibility in dark mode.

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 59f7317 and 59aef69.

📒 Files selected for processing (1)
  • BaseStyle/BaseStyle/Resource/BaseAssets.xcassets/Colors/ErrorColor.colorset/Contents.json (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: build

@canopas canopas deleted a comment from coderabbitai bot Jan 10, 2025
@canopas canopas deleted a comment from coderabbitai bot Jan 10, 2025
@cp-nirali-s
Copy link
Collaborator

cp-nirali-s commented Jan 10, 2025

Let's show success toast on feedback submission.

After adding feedback we are navigating back to user if we add toast then toast will never show that's why we have added alert and on tap of ok btn we are redirecting user to account screen.

Copy link

@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

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 59aef69 and 21f75ec.

📒 Files selected for processing (2)
  • firestore.rules (4 hunks)
  • functions/src/mail/mail_service.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • functions/src/mail/mail_service.ts
🧰 Additional context used
📓 Learnings (1)
firestore.rules (1)
Learnt from: cp-nirali-s
PR: canopas/splito#94
File: functions/src/index.ts:31-33
Timestamp: 2025-01-10T06:13:20.685Z
Learning: Firestore security rules for the feedback collection are managed through the Firebase console instead of source control.
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: build
🔇 Additional comments (2)
firestore.rules (2)

38-42: LGTM! Formatting improvements.

The formatting changes improve readability while maintaining the same security logic.


Line range hint 75-84: LGTM! Proper validation of transaction participants.

The rules correctly ensure that both payer and receiver are members of the group.

firestore.rules Outdated Show resolved Hide resolved
@cp-amisha-i cp-amisha-i force-pushed the add-send-feedback-option branch from 5d5e352 to 7150e04 Compare January 10, 2025 09:02
@cp-amisha-i cp-amisha-i merged commit 6bfeb73 into main Jan 10, 2025
1 of 2 checks passed
@cp-amisha-i cp-amisha-i deleted the add-send-feedback-option branch January 10, 2025 09:09
@coderabbitai coderabbitai bot mentioned this pull request Jan 10, 2025
7 tasks
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