Skip to content

Conversation

@chetanr25
Copy link
Contributor

@chetanr25 chetanr25 commented Apr 20, 2025

What

Created a user dashboard taking inspiration from https://prices.openfoodfacts.org/dashboard

Changes

Screenshot

https://github.com/user-attachments/assets/6818d97b-3998-4f01-8b9e-bf024c96247f
image

Fixes bug(s)

Part of

I’ve tried to stick to the existing codebase conventions for this. If I’ve missed something or anything needs to be changed, please let me know, I will make the updates.

@chetanr25
Copy link
Contributor Author

I had made changes to the Flutter package in my local system to test if this works. I have added the kind parameter in my PR to extend GetPricesParameters() for filtering contributions by type (“Community” or “Consumption”). Since the kind parameter isn’t available yet in the OpenFoodFacts package and I’m trying to use it in this PR, the build test is failing.

Should I comment it out or remove it for now?

@chetanr25
Copy link
Contributor Author

Once the changes from openfoodfacts/openfoodfacts-dart#1065 are available in our Flutter package, we can delete this file packages/smooth_app/lib/data_models/users_profile_data.dart and use the PriceUser model instead.

Untill then should the PR be a Draft PR or is it okay to keep it open?

@teolemon
Copy link
Member

@TTalex @raphodn I definitely would put My Receipts here. The wording is a bit creepy on mobile, given they are public (we do mention they will be public on upload, but still)

@teolemon
Copy link
Member

@chetanr25 can you rename "My Consumption" to "Receipts & GDPR requests", and "Other contributions" to "Price labels" ?

@teolemon
Copy link
Member

error • The setter 'kind' isn't defined for the type 'GetPricesParameters' • packages/smooth_app/lib/pages/prices/prices_dashboard_widget.dart:73:11 • undefined_setter

@teolemon teolemon requested a review from Copilot April 26, 2025 12:35
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Copilot wasn't able to review any files in this pull request.

Files not reviewed (5)
  • packages/smooth_app/lib/data_models/users_profile_data.dart: Language not supported
  • packages/smooth_app/lib/pages/preferences/user_preferences_prices.dart: Language not supported
  • packages/smooth_app/lib/pages/prices/prices_dashboard.dart: Language not supported
  • packages/smooth_app/lib/pages/prices/prices_dashboard_widget.dart: Language not supported
  • packages/smooth_app/lib/pages/prices/prices_user_profile.dart: Language not supported

@teolemon
Copy link
Member

/gemini review

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a user dashboard to the price section, displaying user statistics and recent contributions. The dashboard is inspired by the Open Food Facts prices dashboard and includes a toggle for filtering contributions by type (consumption/community). Overall, the implementation seems well-structured and addresses the feature request. However, there are a few areas that could be improved for better maintainability and clarity.

Summary of Findings

  • TODO comments: There are a couple of TODO comments that indicate areas where the code is not yet fully implemented or needs further attention. It's important to address these before merging to ensure the feature is complete and functional.
  • Error Handling: The error handling in _fetchUserProfile function could be improved to provide more informative error messages to the user.
  • Code Duplication: The logic for determining contribution type ('CONSUMPTION' or 'COMMUNITY') is duplicated in PricesDashboardWidget. Consider centralizing this logic to avoid redundancy.

Merge Readiness

The pull request introduces a valuable feature, but there are a few issues that should be addressed before merging. Specifically, the TODO comments should be resolved, error handling improved, and code duplication reduced. Addressing these points will improve the overall quality and maintainability of the code. I am unable to approve this pull request, and recommend that others review and approve this code before merging.

Comment on lines 73 to 75
..kind = selectedIndex == 0
? 'CONSUMPTION'
: 'COMMUNITY', // TODO(chetanr25): This must be implemented in OpenFoodFacts flutter package

Choose a reason for hiding this comment

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

high

The logic for determining the kind parameter based on selectedIndex is duplicated in the _getUserPrices function and the customToggleButton widget. Consider creating a separate function or constant to encapsulate this logic and avoid redundancy.

@@ -0,0 +1,81 @@
// TODO(chetanr25): To be implemented in OpenFoodFacts flutter package in [https://github.com/openfoodfacts/smooth-app/tree/develop/packages/smooth_app/lib/data_models] as [UserProfile] JsonSerializable

Choose a reason for hiding this comment

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

medium

This TODO indicates that this model should eventually be moved to the openfoodfacts-dart package. It would be good to create an issue in that repo to track this work and link it here.

);
}

// TODO(chetanr25): To be implemented in OpenFoodFacts flutter package

Choose a reason for hiding this comment

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

medium

This TODO indicates that this function should eventually be moved to the openfoodfacts-dart package. It would be good to create an issue in that repo to track this work and link it here.

Comment on lines 74 to 75
//
}

Choose a reason for hiding this comment

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

medium

The catch block is currently empty. At a minimum, log the error for debugging purposes. Ideally, display a user-friendly error message.

    } catch (e) {
      debugPrint('Error fetching user profile: $e'); // Log the error
      // Optionally, display an error message to the user
    }

Comment on lines 73 to 75
..kind = selectedIndex == 0
? 'CONSUMPTION'
: 'COMMUNITY', // TODO(chetanr25): This must be implemented in OpenFoodFacts flutter package

Choose a reason for hiding this comment

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

medium

This TODO indicates that the kind parameter implementation is still pending in the openfoodfacts-dart package. It's important to track the progress of that PR and update this code once it's merged.

Comment on lines 73 to 75
..kind = selectedIndex == 0
? 'CONSUMPTION'
: 'COMMUNITY', // TODO(chetanr25): This must be implemented in OpenFoodFacts flutter package

Choose a reason for hiding this comment

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

medium

Consider using an enum instead of hardcoded strings ('CONSUMPTION', 'COMMUNITY') for the kind parameter. This would improve type safety and readability.

..kind = selectedIndex == 0
            ? PriceKind.consumption
            : PriceKind.community,

@github-project-automation github-project-automation bot moved this from 💬 To discuss and validate to 🏗️ In Progress in 🤳🥫 The Open Food Facts mobile app (Android & iOS) Apr 26, 2025
@chetanr25
Copy link
Contributor Author

error • The setter 'kind' isn't defined for the type 'GetPricesParameters' • packages/smooth_app/lib/pages/prices/prices_dashboard_widget.dart:73:11 • undefined_setter

This has been fixed. Since openfoodfacts/openfoodfacts-dart#1064 is merged and is available in openfoodfacts flutter package, we can now use the ContributionKind enum.

@chetanr25 can you rename "My Consumption" to "Receipts & GDPR requests", and "Other contributions" to "Price labels" ?

I have made the requested changes and committed them to the current PR. Initially, I had replicated the same titles (‘My Consumption’ and ‘Other Contributions’) from the dashboard web version. Since we have updated the titles, is there anything else I should update in the PR to stay consistent?

@monsieurtanuki
Copy link
Contributor

error • The setter 'kind' isn't defined for the type 'GetPricesParameters' • packages/smooth_app/lib/pages/prices/prices_dashboard_widget.dart:73:11 • undefined_setter

This has been fixed. Since openfoodfacts/openfoodfacts-dart#1064 is merged and is available in openfoodfacts flutter package, we can now use the ContributionKind enum.

@chetanr25 No it hasn't been fixed, as we haven't released a new version of openfoodfacts-dart yet.
I don't want to sound old-fashioned or patronizing, but somehow you need to test your code - at least run it.

@chetanr25
Copy link
Contributor Author

I had tested well and only then committing to this PR.
To verify the functionality, I first made changes locally in the openfoodfacts Flutter package within the .pub-cache to test the integration with smooth-app. Since Flutter packages are open source, I directly edited the package code for testing purpose. After confirming that the changes worked correctly, I contributed them to the openfoodfacts-dart repository.

The changes were made for testing purposes, to ensure that everything worked correctly on smooth-app. As a result, it appeared to work without any issues on my local system.

However, I realize now that I forgot the fact that the actual package update had not yet been officially released. I mistakenly assumed that it had already been published and updated the PR.

I completely understand that directly modifying installed packages is not a good practice. I had only done it temporarily for testing. After reinstalling the package, I realized the release hadn’t happened yet.

Apologies for the confusion.

@monsieurtanuki
Copy link
Contributor

@TTalex @raphodn I definitely would put My Receipts here. The wording is a bit creepy on mobile, given they are public (we do mention they will be public on upload, but still)

For the record I still haven't understood which prices are placed where.

@TTalex
Copy link
Collaborator

TTalex commented Apr 27, 2025

For the record I still haven't understood which prices are placed where.

Yeah, it's not obvious :/

By default :

  • Consumption = Receipts & GDPR
  • Community = Price tag & Shop import

Receipts can be added to "Community" if user opt-outs, using boolean owner_consumption in /api/v1/proofs/upload API (useful if you add receipt that are not yours)

@monsieurtanuki
Copy link
Contributor

For the record I still haven't understood which prices are placed where.

Yeah, it's not obvious :/

By default :

  • Consumption = Receipts & GDPR
  • Community = Price tag & Shop import

Thank you @TTalex for your explanations!
My point was also: how relevant is that distinction for a simple user? Wouldn't we be better off displaying simply 4 sections - Receipts, GDPR, Price tag and Shop import?
You would still keep your consumption/community flag.

@teolemon teolemon requested a review from Copilot May 16, 2025 19:49
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR introduces a Dashboard feature for the prices section by adding new UI components and a UserProfile model. Key changes include:

  • A new PricesUserProfile widget to display user statistics.
  • A PricesDashboardWidget that fetches and displays price/proof data with a toggle for contribution types.
  • A PricesDashboard page and an updated user preferences list that link to the new dashboard.

Reviewed Changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
packages/smooth_app/lib/pages/prices/prices_user_profile.dart New widget to display user profile statistics.
packages/smooth_app/lib/pages/prices/prices_dashboard_widget.dart Dashboard widget with contribution type toggling and price/proof fetching.
packages/smooth_app/lib/pages/prices/prices_dashboard.dart Scaffold page assembling the dashboard and profile widgets.
packages/smooth_app/lib/pages/preferences/user_preferences_prices.dart Added ListTile for navigating to the new dashboard.
packages/smooth_app/lib/data_models/users_profile_data.dart Introduced UserProfile model for data deserialization.

Comment on lines 33 to 37
spacing: MEDIUM_SPACE,
children: <Widget>[
categorySwitch(),
const SizedBox(height: SMALL_SPACE),
priceProofButton(widget.userProfile!, appLocalizations),
Copy link

Copilot AI May 16, 2025

Choose a reason for hiding this comment

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

The Column widget does not have a 'spacing' property. Replace it with SizedBox widgets or use a widget that supports spacing.

Suggested change
spacing: MEDIUM_SPACE,
children: <Widget>[
categorySwitch(),
const SizedBox(height: SMALL_SPACE),
priceProofButton(widget.userProfile!, appLocalizations),
children: <Widget>[
categorySwitch(),
const SizedBox(height: MEDIUM_SPACE),
priceProofButton(widget.userProfile!, appLocalizations),
const SizedBox(height: MEDIUM_SPACE),

Copilot uses AI. Check for mistakes.
const SizedBox(height: SMALL_SPACE),
priceProofButton(widget.userProfile!, appLocalizations),
FutureBuilder<MaybeError<GetPricesResult?>>(
future: _getUserPrices(),
Copy link

Copilot AI May 16, 2025

Choose a reason for hiding this comment

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

The FutureBuilder is instantiating a new future every build call rather than using the stored 'pricesFuture'. Replace it with 'pricesFuture' to avoid unnecessary re-fetching.

Suggested change
future: _getUserPrices(),
future: pricesFuture,

Copilot uses AI. Check for mistakes.
@codecov-commenter
Copy link

codecov-commenter commented May 16, 2025

Codecov Report

Attention: Patch coverage is 0% with 166 lines in your changes missing coverage. Please review.

Project coverage is 5.66%. Comparing base (4d9c7fc) to head (7075c4d).
Report is 901 commits behind head on develop.

Files with missing lines Patch % Lines
..._app/lib/pages/prices/prices_dashboard_widget.dart 0.00% 100 Missing ⚠️
...ooth_app/lib/pages/prices/prices_user_profile.dart 0.00% 33 Missing ⚠️
...th_app/lib/pages/prices/prices_dashboard_page.dart 0.00% 26 Missing ⚠️
...lib/pages/preferences/user_preferences_prices.dart 0.00% 5 Missing ⚠️
.../lib/knowledge_panel/knowledge_panels_builder.dart 0.00% 2 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           develop   #6559      +/-   ##
==========================================
- Coverage     9.54%   5.66%   -3.89%     
==========================================
  Files          325     515     +190     
  Lines        16411   30807   +14396     
==========================================
+ Hits          1567    1745     +178     
- Misses       14844   29062   +14218     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

chetanr25 added 2 commits May 27, 2025 22:07
…mporvary UserProfile model with PriceUser model which is created in openfoodfacts flutter package
@teolemon
Copy link
Member

error • Target of URI doesn't exist: 'package:smooth_app/data_models/users_profile_data.dart' • packages/smooth_app/lib/pages/prices/prices_dashboard.dart:4:8 • uri_does_not_exist
error • The name 'UserProfile' isn't a type, so it can't be used as a type argument • packages/smooth_app/lib/pages/prices/prices_dashboard.dart:15:32 • non_type_as_type_argument
error • The name 'UserProfile' isn't a type, so it can't be used as a type argument • packages/smooth_app/lib/pages/prices/prices_dashboard.dart:35:38 • non_type_as_type_argument
error • The name 'UserProfile' isn't a type, so it can't be used as a type argument • packages/smooth_app/lib/pages/prices/prices_dashboard.dart:38:40 • non_type_as_type_argument
error • Undefined class 'UserProfile' • packages/smooth_app/lib/pages/prices/prices_dashboard.dart:45:19 • undefined_class
error • The name 'UserProfile' isn't a type, so it can't be used as a type argument • packages/smooth_app/lib/pages/prices/prices_dashboard.dart:58:28 • non_type_as_type_argument
error • The name 'UserProfile' isn't a type, so it can't be used as a type argument • packages/smooth_app/lib/pages/prices/prices_dashboard.dart:69:27 • non_type_as_type_argument
error • Undefined name 'UserProfile' • packages/smooth_app/lib/pages/prices/prices_dashboard.dart:70:11 • undefined_identifier
error • The name 'UserProfile' isn't a type, so it can't be used as a type argument • packages/smooth_app/lib/pages/prices/prices_dashboard.dart:76:23 • non_type_as_type_argument
error • Target of URI doesn't exist: 'package:smooth_app/data_models/users_profile_data.dart' • packages/smooth_app/lib/pages/prices/prices_dashboard_widget.dart:5:8 • uri_does_not_exist
error • Undefined class 'UserProfile' • packages/smooth_app/lib/pages/prices/prices_dashboard_widget.dart:16:9 • undefined_class
info • Unnecessary use of a null check ('!') • packages/smooth_app/lib/pages/prices/prices_dashboard_widget.dart:37:44 • unnecessary_null_checks
error • Undefined class 'UserProfile' • packages/smooth_app/lib/pages/prices/prices_dashboard_widget.dart:155:7 • undefined_class

@chetanr25
Copy link
Contributor Author

I was actually waiting for openfoodfacts/openfoodfacts-dart#1085 to be released in the openfoodfacts Flutter package so I could use it here.

I'll remove this

// TODO(chetanr25): To be implemented in OpenFoodFacts flutter package
once the package is being published.

@monsieurtanuki
Copy link
Contributor

@chetanr25 I've just released openfoodfacts 3.23.0.

chetanr25 added 2 commits June 18, 2025 15:20
@chetanr25
Copy link
Contributor Author

I have updated the package version in pubspec.yaml file.

For now, i have added a TODO for TitleElementType.PERCENTAGE as this was introduced to openfoodfacts flutter package in PR openfoodfacts/openfoodfacts-dart#1086 was causing an error in packages/smooth_app/lib/knowledge_panel/knowledge_panels_builder.dart file.

I haven't mentioned username in TODO

@monsieurtanuki
Copy link
Contributor

I haven't mentioned username in TODO

@chetanr25 Oh you have to. I suggest @PrimaelQuemerais.

@chetanr25
Copy link
Contributor Author

chetanr25 commented Jun 19, 2025

In the previous commit 7075c4d , I resolved the scrolling functionality issue by refactoring the implementation.

Previously, I was directly using ProductPricesList() within PriceDashboardWidget(), which caused scrolling behavior problems as ProductPricesList() was using InfiniteScrollList and I couldn't find a way to change scroll physics of this widget so that the scroll in PriceDashboardWidget() would look natural.

After analyzing the codebase, I took inspiration from ProductPricesList's implementation and used PriceProductWidget and PriceDataWidget components directly.

This solution resolves the scrolling issues, I'd particularly appreciate review on:

  • Whether this implementation maintains good widget reusability or is it not the correct way to implement as if we change anything in ProductPricesList(), we have to do the same change in this dashboard widget.
  • If there might be a better way to achieve the same functionality

Before / After

{Edited because the videos weren't visible]

@monsieurtanuki
Copy link
Contributor

@chetanr25 I think you'd be better off using InfiniteScrollList given that:

  • it'd be easier to maintain
  • sticking 100% to the current web UI/UX isn't even required, as @teolemon stated here

This PR code could be very simple, with a very simple UI/UX.
I don't know what they'll decide about the UI/UX.

@chetanr25
Copy link
Contributor Author

@chetanr25 I think you'd be better off using InfiniteScrollList given that:

  • it'd be easier to maintain
  • sticking 100% to the current web UI/UX isn't even required, as @teolemon stated here

This PR code could be very simple, with a very simple UI/UX. I don't know what they'll decide about the UI/UX.

I tried to use InfiniteScrollList but this didn't work well in this case since the dashboard uses a variety of widgets and not List<T>

I think you'd be better off using InfiniteScrollList given that:

Just to clarify, do you suggest that we go back to the earlier approach (in before video)?

I implemented this (similar to product_prices_list.dart but without InfiniteScrollList) after keeping maintainability and re-usability in mind.
https://github.com/openfoodfacts/smooth-app/blob/7075c4d46a3632dae85c1f075b0184e1397541a3/packages/smooth_app/lib/pages/prices/prices_dashboard_widget.dart#L82C1-L89C25

I am actually confused, how to go about this.

@monsieurtanuki
Copy link
Contributor

this didn't work well in this case since the dashboard uses a variety of widgets

@chetanr25 That's the point. Either you try to stick to the web UI, or you try to display and code things simply.
Personally I have no interest in that web UI that I find hard to understand.

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

Projects

Status: Backlog

Development

Successfully merging this pull request may close these issues.

Replicate the 'Personal dashboard' view from the Open Prices web app

5 participants