feat: Implements reception search page

Introduces a dedicated search page for reception operations.

Enables navigation to this new page from the 'Reception' quick action component, providing a dedicated interface for searching reception records.

Registers the `ReceptionSearchRoute` to integrate it into the application's secure routing system.

Also updates the empty state message on the reception list for improved localization and user experience.
This commit is contained in:
mandreshope 2025-08-04 15:29:52 +03:00
parent d131928235
commit 0b4e5042cc
6 changed files with 157 additions and 2 deletions

View File

@ -3,3 +3,4 @@ export 'delivery/delivery_page.dart';
export 'inventory/inventory_page.dart';
export 'reception/reception_details_page.dart';
export 'reception/reception_scan_page.dart';
export 'reception/reception_search_page.dart';

View File

@ -48,7 +48,11 @@ class _ReceptionPageState extends ConsumerState<ReceptionPage> {
child: ListView(
children: [
const SizedBox(height: 16),
QuickActionComponent(onTapSearch: () {}),
QuickActionComponent(
onTapSearch: () {
ReceptionSearchRoute().push(context);
},
),
const SizedBox(height: 16),
Consumer(
builder: (_, WidgetRef ref, _) {
@ -67,7 +71,7 @@ class _ReceptionPageState extends ConsumerState<ReceptionPage> {
// ).bodyMedium.copyWith(fontWeight: FontWeight.bold),
// ),
state.receptions.isEmpty == true
? Text('No data')
? Center(child: Text('Aucune donnée trouvée'))
: ListView.builder(
physics: NeverScrollableScrollPhysics(),
primary: true,

View File

@ -0,0 +1,71 @@
import 'package:e_scan/backend/objectbox/entities/stock_picking/stock_picking_record_entity.dart';
import 'package:e_scan/components/components.dart';
import 'package:e_scan/pages/operation/reception/reception_search_page_model.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:e_scan/components/main_appbar_component.dart';
import 'package:e_scan/themes/app_theme.dart';
import 'package:flutter/material.dart';
class ReceptionSearchPage extends ConsumerStatefulWidget {
const ReceptionSearchPage({super.key});
@override
ConsumerState<ReceptionSearchPage> createState() =>
_ReceptionSearchPageState();
}
class _ReceptionSearchPageState extends ConsumerState<ReceptionSearchPage> {
@override
Widget build(BuildContext context) {
final state = ref.watch(receptionSearchPageModelProvider);
final receptions = state.valueOrNull ?? <StockPickingRecordEntity>[];
return Scaffold(
backgroundColor: AppTheme.of(context).primaryBackground,
appBar: MainAppbarComponent(
leading: BackButton(color: AppTheme.of(context).white),
title: "Rechercher une réception",
subTitle: "Opérations d'Entrepôt",
),
body: Column(
children: [
Padding(
padding: const EdgeInsets.all(16),
child: TextFormField(
autofocus: true,
decoration: InputDecoration(
hintText: "Nom de la réception",
filled: true,
fillColor: AppTheme.of(context).secondaryBackground,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: BorderSide.none,
),
),
onChanged: (value) {
ref
.read(receptionSearchPageModelProvider.notifier)
.allByName(name: value);
},
),
),
Expanded(
child: state.isLoading
? Center(child: LoadingProgressComponent())
: receptions.isEmpty
? Center(child: Text('Aucun résultat trouvé'))
: SingleChildScrollView(
child: Column(
children: receptions
.map(
(reception) =>
ListTile(title: Text(reception.name ?? '')),
)
.toList(),
),
),
),
],
),
);
}
}

View File

@ -0,0 +1,37 @@
import 'package:e_scan/backend/api/api_calls.dart';
import 'package:e_scan/backend/objectbox/entities/stock_picking/stock_picking_record_entity.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
final receptionSearchPageModelProvider =
StateNotifierProvider.autoDispose<
ReceptionSearchPageModel,
AsyncValue<List<StockPickingRecordEntity>>
>((ref) {
return ReceptionSearchPageModel();
});
class ReceptionSearchPageModel
extends StateNotifier<AsyncValue<List<StockPickingRecordEntity>>> {
/// Constructor initializes the TaskRepository using the provider reference.
ReceptionSearchPageModel() : super(const AsyncValue.loading());
Future<void> allByName({required String name}) async {
try {
state = AsyncValue.loading();
final res = await ApiCalls.getAllStockPiking();
res.when(
(data) async {
final founds = data
.where((e) => e.name?.contains(name) == true)
.toList();
state = AsyncValue.data(founds);
},
(error) {
state = AsyncValue.error(error, StackTrace.current);
},
);
} catch (e) {
state = AsyncValue.error(e, StackTrace.current);
}
}
}

View File

@ -21,6 +21,7 @@ final appSecureRoutes = $appRoutes;
TypedGoRoute<InventoryRoute>(path: 'InventoryPage'),
TypedGoRoute<ReceptionDetailsRoute>(path: 'ReceptionDetailsPage'),
TypedGoRoute<ReceptionScanRoute>(path: 'ReceptionScanPage'),
TypedGoRoute<ReceptionSearchRoute>(path: 'ReceptionSearchPage'),
],
)
class SecureRoute extends GoRouteData with _$SecureRoute {
@ -122,3 +123,17 @@ class ReceptionScanRoute extends GoRouteData with _$ReceptionScanRoute {
Widget build(BuildContext context, GoRouterState state) =>
ReceptionScanPage(receptionId: receptionId);
}
class ReceptionSearchRoute extends GoRouteData with _$ReceptionSearchRoute {
const ReceptionSearchRoute();
@override
CustomTransitionPage<void> buildPage(
BuildContext context,
GoRouterState state,
) => buildPageWithDefaultTransition(
context: context,
state: state,
child: ReceptionSearchPage(),
);
}

View File

@ -49,6 +49,11 @@ RouteBase get $secureRoute => GoRouteData.$route(
factory: _$ReceptionScanRoute._fromState,
),
GoRouteData.$route(
path: 'ReceptionSearchPage',
factory: _$ReceptionSearchRoute._fromState,
),
],
);
@ -256,3 +261,25 @@ mixin _$ReceptionScanRoute on GoRouteData {
@override
void replace(BuildContext context) => context.replace(location);
}
mixin _$ReceptionSearchRoute on GoRouteData {
static ReceptionSearchRoute _fromState(GoRouterState state) =>
const ReceptionSearchRoute();
@override
String get location =>
GoRouteData.$location('/SecurePage/ReceptionSearchPage');
@override
void go(BuildContext context) => context.go(location);
@override
Future<T?> push<T>(BuildContext context) => context.push<T>(location);
@override
void pushReplacement(BuildContext context) =>
context.pushReplacement(location);
@override
void replace(BuildContext context) => context.replace(location);
}