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
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
74bdfe3
refactor: Implement Timestamp Logic for Creation
fulleni Jul 3, 2025
a83e29b
refactor: Implement Timestamp Logic for Updates
fulleni Jul 3, 2025
6e7a503
feat: added a new createdCategory property to the state. This will al…
fulleni Jul 3, 2025
53ebeb8
feat: updated the _onSubmitted method in create_category_bloc.dart. W…
fulleni Jul 3, 2025
cd02fb8
feat: modify edit_category_state.dart. I'm adding an updatedCategory …
fulleni Jul 3, 2025
229919a
feat: modified the _onSubmitted method in edit_category_bloc.dart. Wh…
fulleni Jul 3, 2025
cd46a81
refactor(content_management): add createdHeadline to CreateHeadlineState
fulleni Jul 3, 2025
d87412d
refactor(content_management): emit created headline object on success
fulleni Jul 3, 2025
2e0fbad
refactor(content_management): add updatedHeadline to EditHeadlineState
fulleni Jul 3, 2025
1707271
fix(content_management): add updatedHeadline property to EditHeadline…
fulleni Jul 3, 2025
36dea0f
refactor(content_management): emit updated headline object on success
fulleni Jul 3, 2025
669f860
refactor(content_management): add createdSource to CreateSourceState
fulleni Jul 3, 2025
88f3541
refactor(content_management): emit created source object on success
fulleni Jul 3, 2025
61dfa2b
refactor(content_management): add an updatedSource property to the st…
fulleni Jul 3, 2025
690d35a
refactor(content_management): update the _onSubmitted method in edit_…
fulleni Jul 3, 2025
c89a9c6
refactor(content_management): introducing new, specific events for ad…
fulleni Jul 3, 2025
28bfafe
refactor(content_management): handle the new local update events. I w…
fulleni Jul 3, 2025
5de9fb5
refactor(content_management): update the BlocListener in create_categ…
fulleni Jul 3, 2025
f5ad54a
refactor(content_management): update the BlocListener in edit_categor…
fulleni Jul 3, 2025
a9801e8
refactor(content_management): update the BlocListener in create_headl…
fulleni Jul 3, 2025
63d0304
refactor(content_management): update the BlocListener in edit_headlin…
fulleni Jul 3, 2025
5e328e5
refactor(content_management): update the BlocListener in create_sourc…
fulleni Jul 3, 2025
cb7b8ad
refactor(content_management): update the BlocListener in edit_source_…
fulleni Jul 3, 2025
2c6fe24
feat(content_management): format updatedAt timestamp in categories table
fulleni Jul 3, 2025
5ba9a38
feat(content_management): format updatedAt timestamp in headlines table
fulleni Jul 3, 2025
90d00c0
feat(content_management): format updatedAt timestamp in sources table
fulleni Jul 3, 2025
4f84cef
style: format
fulleni Jul 3, 2025
6426aa7
lint: misc
fulleni Jul 3, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
242 changes: 72 additions & 170 deletions lib/content_management/bloc/content_management_bloc.dart
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import 'package:bloc/bloc.dart';
import 'package:equatable/equatable.dart';
import 'package:ht_data_repository/ht_data_repository.dart';
import 'package:ht_dashboard/shared/constants/pagination_constants.dart';
import 'package:ht_shared/ht_shared.dart';

part 'content_management_event.dart';
Expand Down Expand Up @@ -31,16 +30,16 @@ class ContentManagementBloc
super(const ContentManagementState()) {
on<ContentManagementTabChanged>(_onContentManagementTabChanged);
on<LoadHeadlinesRequested>(_onLoadHeadlinesRequested);
on<CreateHeadlineRequested>(_onCreateHeadlineRequested);
on<UpdateHeadlineRequested>(_onUpdateHeadlineRequested);
on<HeadlineAdded>(_onHeadlineAdded);
on<HeadlineUpdated>(_onHeadlineUpdated);
on<DeleteHeadlineRequested>(_onDeleteHeadlineRequested);
on<LoadCategoriesRequested>(_onLoadCategoriesRequested);
on<CreateCategoryRequested>(_onCreateCategoryRequested);
on<UpdateCategoryRequested>(_onUpdateCategoryRequested);
on<CategoryAdded>(_onCategoryAdded);
on<CategoryUpdated>(_onCategoryUpdated);
on<DeleteCategoryRequested>(_onDeleteCategoryRequested);
on<LoadSourcesRequested>(_onLoadSourcesRequested);
on<CreateSourceRequested>(_onCreateSourceRequested);
on<UpdateSourceRequested>(_onUpdateSourceRequested);
on<SourceAdded>(_onSourceAdded);
on<SourceUpdated>(_onSourceUpdated);
on<DeleteSourceRequested>(_onOnDeleteSourceRequested);
}

Expand Down Expand Up @@ -93,73 +92,41 @@ class ContentManagementBloc
}
}

Future<void> _onCreateHeadlineRequested(
CreateHeadlineRequested event,
void _onHeadlineAdded(
HeadlineAdded event,
Emitter<ContentManagementState> emit,
) async {
emit(state.copyWith(headlinesStatus: ContentManagementStatus.loading));
try {
await _headlinesRepository.create(item: event.headline);
// Reload headlines after creation
add(
const LoadHeadlinesRequested(limit: kDefaultRowsPerPage),
);
} on HtHttpException catch (e) {
emit(
state.copyWith(
headlinesStatus: ContentManagementStatus.failure,
errorMessage: e.message,
),
);
} catch (e) {
emit(
state.copyWith(
headlinesStatus: ContentManagementStatus.failure,
errorMessage: e.toString(),
),
);
}
) {
final updatedHeadlines = [event.headline, ...state.headlines];
emit(
state.copyWith(
headlines: updatedHeadlines,
headlinesStatus: ContentManagementStatus.success,
),
);
}

Future<void> _onUpdateHeadlineRequested(
UpdateHeadlineRequested event,
void _onHeadlineUpdated(
HeadlineUpdated event,
Emitter<ContentManagementState> emit,
) async {
emit(state.copyWith(headlinesStatus: ContentManagementStatus.loading));
try {
await _headlinesRepository.update(id: event.id, item: event.headline);
// Reload headlines after update
add(
const LoadHeadlinesRequested(limit: kDefaultRowsPerPage),
);
} on HtHttpException catch (e) {
emit(
state.copyWith(
headlinesStatus: ContentManagementStatus.failure,
errorMessage: e.message,
),
);
} catch (e) {
emit(
state.copyWith(
headlinesStatus: ContentManagementStatus.failure,
errorMessage: e.toString(),
),
);
) {
final updatedHeadlines = List<Headline>.from(state.headlines);
final index = updatedHeadlines.indexWhere((h) => h.id == event.headline.id);
if (index != -1) {
updatedHeadlines[index] = event.headline;
emit(state.copyWith(headlines: updatedHeadlines));
}
}

Future<void> _onDeleteHeadlineRequested(
DeleteHeadlineRequested event,
Emitter<ContentManagementState> emit,
) async {
emit(state.copyWith(headlinesStatus: ContentManagementStatus.loading));
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));
Comment on lines 124 to +129

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,
        ),
      );

} on HtHttpException catch (e) {
emit(
state.copyWith(
Expand Down Expand Up @@ -215,73 +182,43 @@ class ContentManagementBloc
}
}

Future<void> _onCreateCategoryRequested(
CreateCategoryRequested event,
void _onCategoryAdded(
CategoryAdded event,
Emitter<ContentManagementState> emit,
) async {
emit(state.copyWith(categoriesStatus: ContentManagementStatus.loading));
try {
await _categoriesRepository.create(item: event.category);
// Reload categories after creation
add(
const LoadCategoriesRequested(limit: kDefaultRowsPerPage),
);
} on HtHttpException catch (e) {
emit(
state.copyWith(
categoriesStatus: ContentManagementStatus.failure,
errorMessage: e.message,
),
);
} catch (e) {
emit(
state.copyWith(
categoriesStatus: ContentManagementStatus.failure,
errorMessage: e.toString(),
),
);
}
) {
final updatedCategories = [event.category, ...state.categories];
emit(
state.copyWith(
categories: updatedCategories,
categoriesStatus: ContentManagementStatus.success,
),
);
}

Future<void> _onUpdateCategoryRequested(
UpdateCategoryRequested event,
void _onCategoryUpdated(
CategoryUpdated event,
Emitter<ContentManagementState> emit,
) async {
emit(state.copyWith(categoriesStatus: ContentManagementStatus.loading));
try {
await _categoriesRepository.update(id: event.id, item: event.category);
// Reload categories after update
add(
const LoadCategoriesRequested(limit: kDefaultRowsPerPage),
);
} on HtHttpException catch (e) {
emit(
state.copyWith(
categoriesStatus: ContentManagementStatus.failure,
errorMessage: e.message,
),
);
} catch (e) {
emit(
state.copyWith(
categoriesStatus: ContentManagementStatus.failure,
errorMessage: e.toString(),
),
);
) {
final updatedCategories = List<Category>.from(state.categories);
final index = updatedCategories.indexWhere(
(c) => c.id == event.category.id,
);
if (index != -1) {
updatedCategories[index] = event.category;
emit(state.copyWith(categories: updatedCategories));
}
}

Future<void> _onDeleteCategoryRequested(
DeleteCategoryRequested event,
Emitter<ContentManagementState> emit,
) async {
emit(state.copyWith(categoriesStatus: ContentManagementStatus.loading));
try {
await _categoriesRepository.delete(id: event.id);
// Reload categories after deletion
add(
const LoadCategoriesRequested(limit: kDefaultRowsPerPage),
);
final updatedCategories = state.categories
.where((c) => c.id != event.id)
.toList();
emit(state.copyWith(categories: updatedCategories));
} on HtHttpException catch (e) {
emit(
state.copyWith(
Expand Down Expand Up @@ -337,73 +274,38 @@ class ContentManagementBloc
}
}

Future<void> _onCreateSourceRequested(
CreateSourceRequested event,
Emitter<ContentManagementState> emit,
) async {
emit(state.copyWith(sourcesStatus: ContentManagementStatus.loading));
try {
await _sourcesRepository.create(item: event.source);
// Reload sources after creation
add(
const LoadSourcesRequested(limit: kDefaultRowsPerPage),
);
} on HtHttpException catch (e) {
emit(
state.copyWith(
sourcesStatus: ContentManagementStatus.failure,
errorMessage: e.message,
),
);
} catch (e) {
emit(
state.copyWith(
sourcesStatus: ContentManagementStatus.failure,
errorMessage: e.toString(),
),
);
}
void _onSourceAdded(SourceAdded event, Emitter<ContentManagementState> emit) {
final updatedSources = [event.source, ...state.sources];
emit(
state.copyWith(
sources: updatedSources,
sourcesStatus: ContentManagementStatus.success,
),
);
}

Future<void> _onUpdateSourceRequested(
UpdateSourceRequested event,
void _onSourceUpdated(
SourceUpdated event,
Emitter<ContentManagementState> emit,
) async {
emit(state.copyWith(sourcesStatus: ContentManagementStatus.loading));
try {
await _sourcesRepository.update(id: event.id, item: event.source);
// Reload sources after update
add(
const LoadSourcesRequested(limit: kDefaultRowsPerPage),
);
} on HtHttpException catch (e) {
emit(
state.copyWith(
sourcesStatus: ContentManagementStatus.failure,
errorMessage: e.message,
),
);
} catch (e) {
emit(
state.copyWith(
sourcesStatus: ContentManagementStatus.failure,
errorMessage: e.toString(),
),
);
) {
final updatedSources = List<Source>.from(state.sources);
final index = updatedSources.indexWhere((s) => s.id == event.source.id);
if (index != -1) {
updatedSources[index] = event.source;
emit(state.copyWith(sources: updatedSources));
}
}

Future<void> _onOnDeleteSourceRequested(
DeleteSourceRequested event,
Emitter<ContentManagementState> emit,
) async {
emit(state.copyWith(sourcesStatus: ContentManagementStatus.loading));
try {
await _sourcesRepository.delete(id: event.id);
// Reload sources after deletion
add(
const LoadSourcesRequested(limit: kDefaultRowsPerPage),
);
final updatedSources = state.sources
.where((s) => s.id != event.id)
.toList();
emit(state.copyWith(sources: updatedSources));
} on HtHttpException catch (e) {
emit(
state.copyWith(
Expand Down
Loading
Loading