Skip to content

Implement timestamp logic for creating and updating items #19

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

Merged

Conversation

fulleni
Copy link
Member

@fulleni fulleni commented Jul 3, 2025

Status

*READY

Description

Implement timestamp logic for creating and updating items

Type of Change

  • ✨ New feature (non-breaking change which adds functionality)
  • 🛠️ Bug fix (non-breaking change which fixes an issue)
  • ❌ Breaking change (fix or feature that would cause existing functionality to change)
  • 🧹 Code refactor
  • ✅ Build configuration change
  • 📝 Documentation
  • 🗑️ Chore

fulleni added 28 commits July 3, 2025 17:12
…low the CreateCategoryBloc to hold the newly created category object upon successful submission, which is the first step toward updating the main list locally instead of doing a full refresh.
…hen a category is successfully created, I'll emit the new Category object along with the success status. This makes the newly created item available in the BLoC's state, which is essential for the UI to perform a local update on the main content list later.
…property. This will allow the EditCategoryBloc to hold the successfully updated category object, which is necessary for the UI to later perform a local update on the main content list.
…en a category is successfully updated, I'll emit the updatedCategory object along with the success status. This makes the updated item available in the BLoC's state, which is crucial for the UI to perform a local update on the main content list.
…ate. This will allow the EditSourceBloc to hold the successfully updated source object, which is the final piece needed before we can refactor the main ContentManagementBloc to handle local updates
…source_bloc.dart. When a source is successfully updated, I'll set the updatedAt timestamp and then emit the complete updatedSource object along with the success status. This makes the updated item available in the BLoC's state, which is the final piece required before we can move on to updating the main ContentManagementBloc.
…ding and updating items (HeadlineAdded, HeadlineUpdated, etc.). These events will carry the actual object, allowing the BLoC to update its list locally without a full refresh. I am also removing the old Create...Requested and Update...Requested events as they are now obsolete.
…ill remove the old, inefficient event handlers that triggered a full data reload and replace them with new handlers that perform fast, local list manipulations (adding, updating, and deleting items directly in the state). This is the core change that will fix the "N/A" timestamp issue and make the UI much more responsive.
…ory_page.dart. Instead of dispatching the old LoadCategoriesRequested event (which caused a full reload), it will now dispatch the new CategoryAdded event. This event carries the newly created category object directly to the ContentManagementBloc, which will add it to the list locally for an instant UI update.
…y_page.dart. When an edit is successful, it will now dispatch the new CategoryUpdated event, passing the updated category object directly to the ContentManagementBloc. This allows the main list to update the specific item locally, which is much more efficient than reloading the entire list.
…ine_page.dart. Instead of triggering a full data reload, it will now dispatch the new HeadlineAdded event. This event passes the newly created headline object directly to the ContentManagementBloc, which will add it to the list locally for an immediate and efficient UI update.
…e_page.dart. When an edit is successful, it will now dispatch the new HeadlineUpdated event, passing the updated headline object directly to the ContentManagementBloc. This allows the main list to update the specific item locally, which is much more efficient than reloading the entire list.
…e_page.dart. Instead of triggering a full data reload, it will now dispatch the new SourceAdded event. This event passes the newly created source object directly to the ContentManagementBloc, which will add it to the list locally for an immediate and efficient UI update.
…page.dart. When an edit is successful, it will dispatch the SourceUpdated event, passing the updated source object directly to the ContentManagementBloc. This completes our UI refactoring, ensuring all create and edit operations result in an efficient local list update rather than a full reload.
@fulleni fulleni merged commit ac15f43 into main Jul 3, 2025
1 check failed
@fulleni fulleni deleted the implement_timestamp_logic_for_creating_and_updating_items branch July 3, 2025 17:46
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.

Summary of Changes

Hello @fulleni, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly refactors the content management system's state handling by introducing direct local state updates for item creation, modification, and deletion. It also integrates automatic timestamping for createdAt and updatedAt fields on all managed content types, enhancing data integrity and providing better visibility into content lifecycle within the UI.

Highlights

  • Enhanced State Management: The ContentManagementBloc has been refactored to directly update its local state (lists of headlines, categories, and sources) upon successful item creation, update, or deletion. This replaces the previous approach of re-fetching all items from the repository, leading to improved responsiveness and efficiency.
  • Timestamp Integration: createdAt and updatedAt timestamps are now automatically applied to Headline, Category, and Source items when they are created or updated, respectively. For headlines, publishedAt is also set on creation.
  • Improved UI Responsiveness: The create and edit pages now dispatch specific 'item added' or 'item updated' events to the ContentManagementBloc after successful operations, passing the newly created or updated item. This allows for immediate UI reflection without requiring a full data reload.
  • UI Display of Timestamps: The updatedAt timestamp is now displayed in a user-friendly dd-MM-yyyy format on the Categories, Headlines, and Sources listing pages.
  • Code Refactoring and Cleanup: Various unused imports have been removed across multiple files, and minor formatting adjustments have been applied for consistency.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point in your pull request via creating an issue comment (i.e. comment on the pull request page) using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in issue comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist is currently in preview and may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments to provide feedback.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

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 timestamping for item creation and updates, and refactors the BLoC layer to support more efficient, optimistic UI updates. The changes are well-structured and significantly improve the architecture by decoupling creation/update forms from the main content list's BLoC. The review focuses on ensuring user feedback during asynchronous delete operations, maintaining consistency in the copyWith method for handling error messages, and updating the status after a successful category creation.

Comment on lines 124 to +129
try {
await _headlinesRepository.delete(id: event.id);
// Reload headlines after deletion
add(
const LoadHeadlinesRequested(limit: kDefaultRowsPerPage),
);
final updatedHeadlines = state.headlines
.where((h) => h.id != event.id)
.toList();
emit(state.copyWith(headlines: updatedHeadlines));

Choose a reason for hiding this comment

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

medium

While updating the state locally after deletion is more efficient than refetching, removing the loading state might lead to a poor user experience on slow networks. Without it, the user receives no feedback that the delete operation is in progress and might try to perform other actions. Consider re-introducing a loading state by emitting it before this try block, and emitting a success status along with the updated list upon successful deletion.

    emit(state.copyWith(headlinesStatus: ContentManagementStatus.loading));
    try {
      await _headlinesRepository.delete(id: event.id);
      final updatedHeadlines =
          state.headlines.where((h) => h.id != event.id).toList();
      emit(
        state.copyWith(
          headlines: updatedHeadlines,
          headlinesStatus: ContentManagementStatus.success,
        ),
      );

@@ -58,17 +61,19 @@ final class EditCategoryState extends Equatable {
iconUrl: iconUrl ?? this.iconUrl,
contentStatus: contentStatus ?? this.contentStatus,
errorMessage: errorMessage ?? this.errorMessage,

Choose a reason for hiding this comment

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

medium

This implementation of copyWith for errorMessage is inconsistent with other state classes in this PR (e.g., EditHeadlineState, EditSourceState). Using errorMessage ?? this.errorMessage prevents clearing an existing error message by passing null. For consistency and more predictable state management, consider changing this to errorMessage: errorMessage.

      errorMessage: errorMessage,

Comment on lines +166 to +172
DataCell(
Text(
category.updatedAt != null
// TODO(fulleni): Make date format configurable by admin.
? DateFormat('dd-MM-yyyy').format(category.updatedAt!.toLocal())
: l10n.notAvailable,
),

Choose a reason for hiding this comment

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

medium

Consider making the date format configurable by admin.

            category.updatedAt != null
                // TODO(fulleni): Make date format configurable by admin.
                ? DateFormat('dd-MM-yyyy').format(category.updatedAt!.toLocal())
                : l10n.notAvailable,

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.

1 participant