Build staff management, store details editing, and a forced PIN change
Wires the last two dead buttons in Settings and closes the loop on the credential work: hashed PINs are only worth having if a shop can actually change them. Users & roles (Manage) - Add, rename, re-role and remove staff. Admin-only at the door, because anyone who can edit staff can make themselves an admin. - PIN and confirmation are both required and must match. There is no email to reset a PIN with, so a typo nobody can verify locks the account out until an admin intervenes. - Editing someone leaves their PIN alone unless a new one is typed. An admin setting another person's PIN counts as a reset and re-arms must-change. - Removal is a deactivation with a confirmation that explains why: bills already rung keep the cashier's name, so shift reports stay correct. - Anyone still on a shipped PIN is flagged in the list and in Settings. Store details (Edit) - Name, address, GSTIN and phone now editable and persisted. GSTIN is format and state-code validated; it prints on every invoice as a legal requirement, so a typo is a compliance problem across hundreds of bills. - Admin-only: changing the GSTIN changes what every future invoice claims about who collected the tax. Forced PIN change - Shown once after sign-in while must-change is set, and not dismissable. The seeded PINs are in the source of the build, so a terminal still running one is effectively unprotected. Fixed while testing: the role dropdown laid its items out at natural width and "Manager — Sales, inventory and reports" overflowed the dialog by 222px. Now isExpanded with the description spelled out below, where it is readable. Tests: 160 -> 168. Covers both role guards, the mismatched and too-short PIN paths, the default-PIN flag, and GSTIN and seller-name validation. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -6,11 +6,13 @@ import '../../../core/services/barcode_service.dart';
|
||||
import '../../../core/theme/app_colors.dart';
|
||||
import '../../../core/theme/app_dimens.dart';
|
||||
import '../../../core/theme/app_layout.dart';
|
||||
import '../../auth/providers/auth_controller.dart';
|
||||
import '../../modules/screens/customers_view.dart';
|
||||
import '../../modules/screens/events_view.dart';
|
||||
import '../../modules/screens/product_import_view.dart';
|
||||
import '../../modules/screens/promos_view.dart';
|
||||
import '../../modules/screens/settings_view.dart';
|
||||
import '../../modules/widgets/staff_dialogs.dart';
|
||||
import '../../sync/providers/sync_controller.dart';
|
||||
import '../providers/cart_controller.dart';
|
||||
import '../providers/catalog_providers.dart';
|
||||
@@ -45,10 +47,18 @@ class _PosDashboardScreenState extends ConsumerState<PosDashboardScreen> {
|
||||
final FocusNode _searchFocus = FocusNode();
|
||||
late final BarcodeService _barcode;
|
||||
|
||||
/// Guards against re-opening the PIN dialog on every rebuild.
|
||||
bool _promptedForPin = false;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
|
||||
// Anyone still on a PIN this build shipped with is asked to choose their
|
||||
// own before ringing a sale. Deferred to the first frame because it opens
|
||||
// a dialog, which needs a Navigator that exists.
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) => _maybePromptForPin());
|
||||
|
||||
// The scanner behaves like a keyboard, so listen globally rather than
|
||||
// depending on any one field holding focus. A scan from another module
|
||||
// jumps back to billing, which is what a cashier expects.
|
||||
@@ -65,6 +75,14 @@ class _PosDashboardScreenState extends ConsumerState<PosDashboardScreen> {
|
||||
)..attach();
|
||||
}
|
||||
|
||||
Future<void> _maybePromptForPin() async {
|
||||
if (_promptedForPin || !mounted) return;
|
||||
if (!ref.read(mustChangePinProvider)) return;
|
||||
|
||||
_promptedForPin = true;
|
||||
await showForcedPinChange(context);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_barcode.dispose();
|
||||
|
||||
Reference in New Issue
Block a user