Skip to content

Commit 1a657e7

Browse files
Merge branch 'NetManagerMapFunc' of github.com:AKATWIJUKA-ELIA/AirQo-frontend into NetManagerMapFunc
2 parents 326ea68 + 178e929 commit 1a657e7

File tree

28 files changed

+669
-455
lines changed

28 files changed

+669
-455
lines changed

mobile-v3/assets/images/shared/Frame 128.svg

Lines changed: 28 additions & 0 deletions
Loading

mobile-v3/lib/main.dart

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
import 'dart:io';
2-
32
import 'package:airqo/src/app/auth/bloc/ForgotPasswordBloc/forgot_password_bloc.dart';
43
import 'package:airqo/src/app/auth/bloc/auth_bloc.dart';
5-
import 'package:airqo/src/app/auth/pages/password_reset/forgot_password.dart';
64
import 'package:airqo/src/app/auth/pages/welcome_screen.dart';
75
import 'package:airqo/src/app/auth/repository/auth_repository.dart';
86
import 'package:airqo/src/app/dashboard/bloc/dashboard/dashboard_bloc.dart';
@@ -21,9 +19,7 @@ import 'package:airqo/src/app/profile/bloc/user_bloc.dart';
2119
import 'package:airqo/src/app/profile/repository/user_repository.dart';
2220
import 'package:airqo/src/app/shared/bloc/connectivity_bloc.dart';
2321
import 'package:airqo/src/app/shared/pages/nav_page.dart';
24-
2522
import 'package:airqo/src/meta/utils/colors.dart';
26-
2723
import 'package:connectivity_plus/connectivity_plus.dart';
2824
import 'package:flutter/material.dart';
2925
import 'package:flutter_bloc/flutter_bloc.dart';
@@ -92,7 +88,7 @@ class AirqoMobile extends StatelessWidget {
9288
return MultiBlocProvider(
9389
providers: [
9490
BlocProvider(
95-
create: (context) => AuthBloc(authRepository),
91+
create: (context) => AuthBloc(authRepository)..add(AppStarted()),
9692
),
9793
BlocProvider(
9894
create: (context) => ForecastBloc(forecastRepository),
@@ -164,11 +160,14 @@ class _DeciderState extends State<Decider> {
164160
children: [
165161
FutureBuilder<String?>(
166162
future: HiveRepository.getData('token', HiveBoxNames.authBox),
163+
167164
builder: (context, snapshot) {
165+
166+
168167
// Handle loading state
169168
if (snapshot.connectionState == ConnectionState.waiting) {
170169
return Scaffold(
171-
body: Center(child: CircularProgressIndicator()),
170+
body: const Center(child: CircularProgressIndicator()),
172171
);
173172
}
174173
if (snapshot.connectionState == ConnectionState.done) {

mobile-v3/lib/src/app/auth/bloc/auth_bloc.dart

Lines changed: 110 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -4,46 +4,122 @@ import 'package:bloc/bloc.dart';
44
import 'package:equatable/equatable.dart';
55
import 'package:flutter/cupertino.dart';
66

7+
import '../../shared/repository/hive_repository.dart';
8+
79
part 'auth_event.dart';
810
part 'auth_state.dart';
911

12+
// class AuthBloc extends Bloc<AuthEvent, AuthState> {
13+
// final AuthRepository authRepository;
14+
// AuthBloc(this.authRepository) : super(AuthInitial()) {
15+
// on<AuthEvent>((event, emit) async {
16+
// if (event is LoginUser) {
17+
// try {
18+
// emit(AuthLoading());
19+
// await authRepository.loginWithEmailAndPassword(
20+
// event.username, event.password);
21+
//
22+
// emit(AuthLoaded(AuthPurpose.LOGIN));
23+
// } catch (e) {
24+
// debugPrint(e.toString());
25+
// emit(
26+
// AuthLoadingError(
27+
// e.toString(),
28+
// ),
29+
// );
30+
// }
31+
// } else if (event is RegisterUser) {
32+
// try {
33+
// emit(AuthLoading());
34+
//
35+
// await authRepository.registerWithEmailAndPassword(event.model);
36+
//
37+
// emit(AuthLoaded(AuthPurpose.REGISTER));
38+
// } catch (e) {
39+
// debugPrint(e.toString());
40+
// emit(
41+
// AuthLoadingError(
42+
// e.toString(),
43+
// ),
44+
// );
45+
// }
46+
// } else if (event is UseAsGuest) {
47+
// emit(GuestUser());
48+
// }
49+
// });
50+
// }
51+
// }
1052
class AuthBloc extends Bloc<AuthEvent, AuthState> {
1153
final AuthRepository authRepository;
54+
1255
AuthBloc(this.authRepository) : super(AuthInitial()) {
13-
on<AuthEvent>((event, emit) async {
14-
if (event is LoginUser) {
15-
try {
16-
emit(AuthLoading());
17-
await authRepository.loginWithEmailAndPassword(
18-
event.username, event.password);
19-
20-
emit(AuthLoaded(AuthPurpose.LOGIN));
21-
} catch (e) {
22-
debugPrint(e.toString());
23-
emit(
24-
AuthLoadingError(
25-
e.toString(),
26-
),
27-
);
28-
}
29-
} else if (event is RegisterUser) {
30-
try {
31-
emit(AuthLoading());
32-
33-
await authRepository.registerWithEmailAndPassword(event.model);
34-
35-
emit(AuthLoaded(AuthPurpose.REGISTER));
36-
} catch (e) {
37-
debugPrint(e.toString());
38-
emit(
39-
AuthLoadingError(
40-
e.toString(),
41-
),
42-
);
43-
}
44-
} else if (event is UseAsGuest) {
45-
emit(GuestUser());
56+
//debugPrint("AuthBloc initialized");
57+
58+
on<AppStarted>(_onAppStarted);
59+
60+
61+
on<LoginUser>(_onLoginUser);
62+
63+
64+
on<RegisterUser>(_onRegisterUser);
65+
66+
67+
on<UseAsGuest>((event, emit) => emit(GuestUser()));
68+
}
69+
70+
71+
Future<void> _onAppStarted(AppStarted event, Emitter<AuthState> emit) async {
72+
emit(AuthLoading());
73+
try {
74+
await Future.delayed(const Duration(milliseconds: 500));
75+
final token = await HiveRepository.getData('token', HiveBoxNames.authBox);
76+
77+
if (token != null && token.isNotEmpty) {
78+
emit(AuthLoaded(AuthPurpose.LOGIN)); // User is logged in
79+
} else {
80+
emit(GuestUser()); // No token found, proceed as guest
4681
}
47-
});
82+
} catch (e) {
83+
debugPrint("Error checking auth state: $e");
84+
emit(AuthLoadingError("Failed to check authentication state."));
85+
}
86+
}
87+
88+
89+
Future<void> _onLoginUser(LoginUser event, Emitter<AuthState> emit) async {
90+
emit(AuthLoading());
91+
try {
92+
93+
final token = await authRepository.loginWithEmailAndPassword(event.username, event.password);
94+
await HiveRepository.saveData(HiveBoxNames.authBox, 'token', token);
95+
// Save token in Hive
96+
final savedToken = await HiveRepository.getData('token', HiveBoxNames.authBox);
97+
//debugPrint("Saved token: $savedToken");
98+
99+
emit(AuthLoaded(AuthPurpose.LOGIN));
100+
} catch (e) {
101+
debugPrint("Login error: $e");
102+
emit(AuthLoadingError(_extractErrorMessage(e)));
103+
}
104+
}
105+
106+
107+
Future<void> _onRegisterUser(RegisterUser event, Emitter<AuthState> emit) async {
108+
emit(AuthLoading());
109+
try {
110+
await authRepository.registerWithEmailAndPassword(event.model);
111+
emit(AuthLoaded(AuthPurpose.REGISTER));
112+
} catch (e) {
113+
debugPrint("Registration error: $e");
114+
emit(AuthLoadingError(_extractErrorMessage(e)));
115+
}
116+
}
117+
118+
119+
String _extractErrorMessage(dynamic e) {
120+
if (e is Exception) {
121+
return e.toString().replaceAll("Exception:", "").trim();
122+
}
123+
return "An unknown error occurred.";
48124
}
49125
}

mobile-v3/lib/src/app/auth/bloc/auth_event.dart

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ sealed class AuthEvent extends Equatable {
77
List<Object> get props => [];
88
}
99

10+
class AppStarted extends AuthEvent {}
11+
12+
1013
class LoginUser extends AuthEvent {
1114
final String username;
1215
final String password;

mobile-v3/lib/src/app/auth/repository/auth_repository.dart

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import 'package:http/http.dart';
88

99
abstract class AuthRepository {
1010
//login function
11-
Future<void> loginWithEmailAndPassword(String username, String password);
11+
Future<String> loginWithEmailAndPassword(String username, String password);
1212
Future<void> registerWithEmailAndPassword(RegisterInputModel model);
1313
Future<String> requestPasswordReset(String email);
1414
Future<String> updatePassword({
@@ -20,7 +20,7 @@ abstract class AuthRepository {
2020

2121
class AuthImpl extends AuthRepository {
2222
@override
23-
Future<void> loginWithEmailAndPassword(String username,
23+
Future<String> loginWithEmailAndPassword(String username,
2424
String password) async {
2525
Response loginResponse = await http.post(
2626
Uri.parse("https://api.airqo.net/api/v2/users/loginUser"),
@@ -42,6 +42,8 @@ class AuthImpl extends AuthRepository {
4242
HiveRepository.saveData(HiveBoxNames.authBox, "token", token);
4343
HiveRepository.saveData(HiveBoxNames.authBox, "userId", userId);
4444
}
45+
46+
return data["token"];
4547
}
4648

4749
@override

mobile-v3/lib/src/app/profile/pages/guest_profile page.dart

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import 'package:airqo/src/app/auth/pages/login_page.dart';
12
import 'package:airqo/src/app/profile/pages/widgets/guest_settings_widget.dart';
23
//import 'package:airqo/src/app/profile/pages/widgets/settings_tile.dart';
34
import 'package:flutter/cupertino.dart';
@@ -134,12 +135,53 @@ class _GuestProfilePageState extends State<GuestProfilePage> {
134135
),
135136
),
136137
),
138+
139+
SizedBox(
140+
height: 18,
141+
),
142+
InkWell(
143+
onTap: () => Navigator.of(context).pushAndRemoveUntil(MaterialPageRoute(
144+
builder: (context) => LoginPage()),(route) => false, ),
145+
child: Container(
146+
height: 56,
147+
decoration: BoxDecoration(
148+
color: AppColors.backgroundColor2,
149+
border: Border.all(
150+
color: AppColors.borderColor2
151+
),
152+
borderRadius:
153+
BorderRadius.circular(4)),
154+
child: Center(
155+
child: isLoading
156+
? Spinner()
157+
: Text(
158+
"Login",
159+
style: TextStyle(
160+
fontWeight: FontWeight.w500,
161+
color: Colors.black,
162+
),
163+
),
164+
),
165+
),
166+
),
137167
SizedBox(
138168
height: 76,
139169
),
140170

141171
Center(
142-
child: SvgPicture.asset('assets/images/shared/Frame 26085560.svg')
172+
child: Column(
173+
children: [
174+
SvgPicture.asset('assets/images/shared/logo.svg',),
175+
SizedBox(height: 18,),
176+
Text(
177+
"3.40.1(1)",
178+
style: TextStyle(color: Theme.of(context).textTheme.headlineMedium?.color),),
179+
SizedBox(height: 18,),
180+
SvgPicture.asset('assets/images/shared/Frame 128.svg',
181+
color: Theme.of(context).textTheme.titleLarge?.color,)
182+
],
183+
),
184+
143185
),
144186
SizedBox(
145187
height: 220,

mobile-v3/lib/src/app/shared/repository/hive_repository.dart

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,10 @@ class HiveBoxNames {
1010
class HiveRepository {
1111
HiveRepository._();
1212

13-
static Future<void> saveData(String boxName, String key, value) async {
13+
static Future<dynamic> saveData(String boxName, String key, dynamic value) async {
1414
var box = await Hive.openBox(boxName);
1515
await box.put(key, value);
16+
return value;
1617
}
1718

1819
static Future<String?> getData(String key, String boxName) async {

mobile-v3/lib/src/meta/utils/colors.dart

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,10 @@ class AppColors {
88
// static Color highlightColor = Color(0xff2E2F33);
99
// static Color boldHeadlineColor = Color(0xff9EA3AA);
1010
// static Color secondaryHeadlineColor = Color(0xff60646C);
11-
11+
//#FAFAFA #E1E7EC
1212
static Color primaryColor = Color(0xff145FFF);
13+
static Color backgroundColor2 = Color(0xffFAFAFA);
14+
static Color borderColor2 = Color(0xffE1E7EC);
1315
static Color backgroundColor = Color(0xffF9FAFB);
1416
static Color highlightColor = Color(0xffF3F6F8);
1517
static Color boldHeadlineColor = Color(0xff6F87A1);

website2/next.config.mjs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,20 @@ const nextConfig = {
3434
},
3535
],
3636
},
37+
async redirects() {
38+
return [
39+
{
40+
source: '/clean-air/forum',
41+
destination: '/clean-air-forum/about?slug=clean-air-forum-2024',
42+
permanent: true,
43+
},
44+
{
45+
source: '/clean-air-forum',
46+
destination: '/clean-air-forum/about',
47+
permanent: true,
48+
},
49+
];
50+
},
3751
};
3852

3953
export default nextConfig;

0 commit comments

Comments
 (0)