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:
@@ -12,6 +12,8 @@ import '../../../domain/entities/store_account.dart';
|
||||
import '../../auth/providers/auth_controller.dart';
|
||||
import '../providers/printer_settings.dart';
|
||||
import '../widgets/back_office_dialog.dart';
|
||||
import '../widgets/staff_dialogs.dart';
|
||||
import '../widgets/store_details_dialog.dart';
|
||||
import '../../sync/providers/sync_controller.dart';
|
||||
import '../widgets/module_widgets.dart';
|
||||
|
||||
@@ -82,7 +84,10 @@ class _SettingsViewState extends ConsumerState<SettingsView> {
|
||||
Widget _storeCard(StoreAccount? store) => PanelCard(
|
||||
title: 'Store details',
|
||||
subtitle: 'Printed on every invoice',
|
||||
action: TextButton(onPressed: () {}, child: const Text('Edit')),
|
||||
action: TextButton(
|
||||
onPressed: () => showStoreDetailsDialog(context),
|
||||
child: const Text('Edit'),
|
||||
),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
@@ -296,7 +301,10 @@ class _SettingsViewState extends ConsumerState<SettingsView> {
|
||||
|
||||
Widget _staffCard(StoreAccount? store, StaffUser? current) => PanelCard(
|
||||
title: 'Users & roles',
|
||||
action: TextButton(onPressed: () {}, child: const Text('Manage')),
|
||||
action: TextButton(
|
||||
onPressed: () => showStaffDialog(context),
|
||||
child: const Text('Manage'),
|
||||
),
|
||||
child: ResponsiveTable(
|
||||
stackBelow: 360,
|
||||
columns: const [
|
||||
@@ -308,10 +316,12 @@ class _SettingsViewState extends ConsumerState<SettingsView> {
|
||||
.map((s) => [
|
||||
Cell(s.name, bold: true),
|
||||
Cell(s.role.label, color: AppColors.textSecondary),
|
||||
s.id == current?.id
|
||||
? const TagChip('Signed in',
|
||||
color: AppColors.success,)
|
||||
: const SizedBox.shrink(),
|
||||
if (s.id == current?.id)
|
||||
const TagChip('Signed in', color: AppColors.success)
|
||||
else if (s.mustChangePin)
|
||||
const TagChip('Default PIN', color: AppColors.warning)
|
||||
else
|
||||
const SizedBox.shrink(),
|
||||
],)
|
||||
.toList(),
|
||||
),
|
||||
|
||||
Reference in New Issue
Block a user