Fix org creation from initial state and wrong password error handling
- Organization creation now works even before orgs are loaded (fixes state guard) - Org creation UI now preserves state and shows inline error messages - Wrong password login no longer triggers global logout; shows inline error instead - ApiClient now excludes /auth/ endpoints from global 401 session expiry
This commit is contained in:
@@ -97,41 +97,56 @@ class OrganizationBloc extends Bloc<OrganizationEvent, OrganizationState> {
|
|||||||
CreateOrganization event,
|
CreateOrganization event,
|
||||||
Emitter<OrganizationState> emit,
|
Emitter<OrganizationState> emit,
|
||||||
) async {
|
) async {
|
||||||
final currentState = state;
|
|
||||||
if (currentState is OrganizationLoaded) {
|
|
||||||
final name = event.name.trim();
|
final name = event.name.trim();
|
||||||
if (name.isEmpty) {
|
if (name.isEmpty) {
|
||||||
|
// Try to preserve current state if possible
|
||||||
|
if (state is OrganizationLoaded) {
|
||||||
emit(
|
emit(
|
||||||
OrganizationLoaded(
|
OrganizationLoaded(
|
||||||
organizations: currentState.organizations,
|
organizations: (state as OrganizationLoaded).organizations,
|
||||||
selectedOrg: currentState.selectedOrg,
|
selectedOrg: (state as OrganizationLoaded).selectedOrg,
|
||||||
isLoading: false,
|
isLoading: false,
|
||||||
error: 'Organization name cannot be empty',
|
error: 'Organization name cannot be empty',
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (currentState.organizations.any((org) => org.name == name)) {
|
|
||||||
|
// Get existing organizations list
|
||||||
|
List<Organization> existingOrgs = [];
|
||||||
|
Organization? selectedOrg;
|
||||||
|
|
||||||
|
if (state is OrganizationLoaded) {
|
||||||
|
existingOrgs = (state as OrganizationLoaded).organizations;
|
||||||
|
selectedOrg = (state as OrganizationLoaded).selectedOrg;
|
||||||
|
|
||||||
|
// Check for duplicate name (client-side validation)
|
||||||
|
if (existingOrgs.any((org) => org.name == name)) {
|
||||||
emit(
|
emit(
|
||||||
OrganizationLoaded(
|
OrganizationLoaded(
|
||||||
organizations: currentState.organizations,
|
organizations: existingOrgs,
|
||||||
selectedOrg: currentState.selectedOrg,
|
selectedOrg: selectedOrg,
|
||||||
isLoading: false,
|
isLoading: false,
|
||||||
error: 'Organization with this name already exists',
|
error: 'Organization with this name already exists',
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set loading state
|
||||||
emit(
|
emit(
|
||||||
OrganizationLoaded(
|
OrganizationLoaded(
|
||||||
organizations: currentState.organizations,
|
organizations: existingOrgs,
|
||||||
selectedOrg: currentState.selectedOrg,
|
selectedOrg: selectedOrg,
|
||||||
isLoading: true,
|
isLoading: true,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
final newOrg = await orgApi.createOrganization(name);
|
final newOrg = await orgApi.createOrganization(name);
|
||||||
final updatedOrgs = [...currentState.organizations, newOrg];
|
final updatedOrgs = [...existingOrgs, newOrg];
|
||||||
emit(
|
emit(
|
||||||
OrganizationLoaded(organizations: updatedOrgs, selectedOrg: newOrg),
|
OrganizationLoaded(organizations: updatedOrgs, selectedOrg: newOrg),
|
||||||
);
|
);
|
||||||
@@ -143,13 +158,12 @@ class OrganizationBloc extends Bloc<OrganizationEvent, OrganizationState> {
|
|||||||
} catch (e) {
|
} catch (e) {
|
||||||
emit(
|
emit(
|
||||||
OrganizationLoaded(
|
OrganizationLoaded(
|
||||||
organizations: currentState.organizations,
|
organizations: existingOrgs,
|
||||||
selectedOrg: currentState.selectedOrg,
|
selectedOrg: selectedOrg,
|
||||||
isLoading: false,
|
isLoading: false,
|
||||||
error: _getErrorMessage(e),
|
error: _getErrorMessage(e),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,9 +29,14 @@ class ApiClient {
|
|||||||
},
|
},
|
||||||
onError: (error, handler) async {
|
onError: (error, handler) async {
|
||||||
if (error.response?.statusCode == 401) {
|
if (error.response?.statusCode == 401) {
|
||||||
|
final path = error.requestOptions.path;
|
||||||
|
// Do not expire session for auth endpoints; show inline error instead
|
||||||
|
final isAuthEndpoint = path.startsWith('/auth/');
|
||||||
|
if (!isAuthEndpoint) {
|
||||||
// Session expired, trigger logout
|
// Session expired, trigger logout
|
||||||
_sessionBloc.add(SessionExpired());
|
_sessionBloc.add(SessionExpired());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return handler.next(error);
|
return handler.next(error);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
|||||||
Reference in New Issue
Block a user