Add Personal tab and fix org selection + API error handling

This commit is contained in:
Leon Bösche
2026-01-11 03:01:58 +01:00
parent 56526c8fc5
commit a51c0e070c
4 changed files with 45 additions and 14 deletions

View File

@@ -73,10 +73,18 @@ class OrganizationBloc extends Bloc<OrganizationEvent, OrganizationState> {
) {
final currentState = state;
if (currentState is OrganizationLoaded) {
final selected = currentState.organizations.firstWhere(
(org) => org.id == event.orgId,
orElse: () => currentState.selectedOrg!,
);
Organization? selected;
if (event.orgId.isEmpty) {
// Personal workspace - set to null to indicate no org selected
selected = null;
} else {
selected = currentState.organizations.firstWhere(
(org) => org.id == event.orgId,
orElse: () => currentState.selectedOrg!,
);
}
emit(
OrganizationLoaded(
organizations: currentState.organizations,

View File

@@ -95,13 +95,13 @@ class _MainAppState extends State<MainApp> {
theme: AppTheme.darkTheme,
home: const Scaffold(
body: Center(
child: CircularProgressIndicator(
valueColor: AlwaysStoppedAnimation<Color>(
AppTheme.accentColor,
child: CircularProgressIndicator(
valueColor: AlwaysStoppedAnimation<Color>(
AppTheme.accentColor,
),
),
),
),
),
);
}
return MaterialApp.router(

View File

@@ -131,8 +131,9 @@ class _HomePageState extends State<HomePage> with TickerProviderStateMixin {
final name = controller.text.trim();
if (name.isNotEmpty) {
// Use the parent context, not the dialog context
BlocProvider.of<OrganizationBloc>(context)
.add(CreateOrganization(name));
BlocProvider.of<OrganizationBloc>(
context,
).add(CreateOrganization(name));
Navigator.of(dialogContext).pop();
}
},
@@ -151,8 +152,9 @@ class _HomePageState extends State<HomePage> with TickerProviderStateMixin {
final name = controller.text.trim();
if (name.isNotEmpty) {
// Use the parent context, not the dialog context
BlocProvider.of<OrganizationBloc>(context)
.add(CreateOrganization(name));
BlocProvider.of<OrganizationBloc>(
context,
).add(CreateOrganization(name));
Navigator.of(dialogContext).pop();
}
},
@@ -189,6 +191,18 @@ class _HomePageState extends State<HomePage> with TickerProviderStateMixin {
children: [
Row(
children: [
// Personal workspace button (always show when logged in)
_buildOrgButton(
Organization(id: '', name: 'Personal'),
selectedOrg == null,
() {
context.read<OrganizationBloc>().add(
SelectOrganization(''),
);
},
),
const SizedBox(width: 16),
// Organization tabs
...orgs.map(
(org) => Row(
children: [

View File

@@ -120,8 +120,17 @@ class ApiClient {
);
}
String code = data?['code'] ?? 'UNKNOWN';
String message = data?['message'] ?? 'Unknown error';
// Only try to extract code/message if data is a Map
String code = 'UNKNOWN';
String message = 'Unknown error';
if (data is Map<String, dynamic>) {
code = data['code'] ?? 'UNKNOWN';
message = data['message'] ?? 'Unknown error';
} else if (data != null) {
message = data.toString();
}
return ApiError(code: code, message: message, status: status);
}
}