Skip to content

Commit 8148cba

Browse files
Merge pull request #118 from PennyPilot/feature/edit-salary
Feature/edit salary
2 parents c78c2c4 + 558236c commit 8148cba

12 files changed

Lines changed: 393 additions & 7 deletions

File tree

lib/core/di/cubit_di.dart

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import 'package:moneyplus/domain/repository/user_money_repository.dart';
66
import 'package:moneyplus/domain/validator/authentication_validator.dart';
77
import 'package:moneyplus/presentation/account_setup/cubit/account_setup_cubit.dart';
88
import 'package:moneyplus/presentation/createAccount/cubit/create_account_cubit.dart';
9+
import 'package:moneyplus/presentation/edit_salary/salary_settings_cubit.dart';
910
import 'package:moneyplus/presentation/home/cubit/home_cubit.dart';
1011
import 'package:moneyplus/presentation/income/cubit/add_income_cubit.dart';
1112
import 'package:moneyplus/presentation/login/cubit/login_cubit.dart';
@@ -43,6 +44,7 @@ void initCubitDI() {
4344
userMoneyRepository: getIt<UserMoneyRepository>(),
4445
),
4546
);
47+
4648
getIt.registerFactory<AddIncomeCubit>(
4749
() => AddIncomeCubit(
4850
transactionRepository: getIt<TransactionRepository>(),
@@ -71,7 +73,12 @@ void initCubitDI() {
7173
getIt<AuthenticationRepository>(),
7274
),
7375
);
76+
7477
getIt.registerFactory<AccountCubit>(
75-
() => AccountCubit(getIt<AccountRepository>()),
78+
() => AccountCubit(getIt<AccountRepository>()),
79+
);
80+
81+
getIt.registerFactory<SalarySettingsCubit>(
82+
() => SalarySettingsCubit(userMoneyRepository: getIt<UserMoneyRepository>()),
7683
);
7784
}

lib/core/l10n/app_ar.arb

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,9 @@
156156
"categoriesBreakdown": "تفاصيل الفئات",
157157
"no_monthly_breakdown": "لا يوجد نفقات لتحليلها بعد",
158158
"totalSpend": "إجمالي الإنفاق",
159+
"salary_saved": "تم حفظ إعدادات الراتب بنجاح",
160+
"failed_to_save_salary": "فشل في حفظ إعدادات الراتب",
161+
"failed_to_load_salary_settings": "فشل في تحميل إعدادات الراتب",
159162
"cancel": "إلغاء",
160163
"english": "الإنجليزية",
161164
"arabic": "العربية",

lib/core/l10n/app_en.arb

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,9 @@
174174
"categoriesBreakdown": "Categories Breakdown",
175175
"no_monthly_breakdown": "No expenses to analyze yet",
176176
"totalSpend": "Total Spend",
177+
"salary_saved": "Salary settings saved successfully",
178+
"failed_to_save_salary": "Failed to save salary settings",
179+
"failed_to_load_salary_settings": "Failed to load salary settings",
177180
"cancel": "Cancel",
178181
"english": "English",
179182
"arabic": "Arabic",

lib/data/repository/user_money_repository.dart

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ class UserRepositoryImpl implements UserMoneyRepository {
8181
}
8282

8383
List<TopSpendingCategory> _getTopSpendingCategoriesFromResponseRows(
84-
List<dynamic> rows,
84+
List<dynamic> rows,
8585
) {
8686
return rows.map((row) {
8787
final data = row as Map<String, dynamic>;
@@ -100,9 +100,9 @@ class UserRepositoryImpl implements UserMoneyRepository {
100100

101101
@override
102102
Future<Currency> getCurrency() async {
103-
final client = await service.getClient();
104-
final response = await client.rpc('get_default_currency');
105-
return Currency.fromJson(response);
103+
final client = await service.getClient();
104+
final response = await client.rpc('get_default_currency');
105+
return Currency.fromJson(response);
106106
}
107107

108108
@override
@@ -133,6 +133,35 @@ class UserRepositoryImpl implements UserMoneyRepository {
133133
return ((currentMonthBalance - previousMonthBalance) / previousMonthBalance) * 100;
134134
}
135135

136+
@override
137+
Future<double> getSalary() async {
138+
final client = await service.getClient();
139+
final response = await client.from('users').select('salary_amount');
140+
final balance = (response.firstOrNull?['salary_amount'] as num?)?.toDouble() ?? 0.0;
141+
return balance;
142+
}
143+
144+
@override
145+
Future<int> getSalaryDay() async {
146+
final client = await service.getClient();
147+
final response = await client.from('users').select('salary_day');
148+
final balance = (response.firstOrNull?['salary_day'] as int?)?.toInt() ?? 0;
149+
return balance;
150+
}
151+
152+
@override
153+
Future<void> updateSalarySettings({
154+
required double salary,
155+
required int salaryDay,
156+
}) async {
157+
final client = await service.getClient();
158+
159+
await client
160+
.from('users')
161+
.update({'salary_amount': salary, 'salary_day': salaryDay})
162+
.eq('id', client.auth.currentUser!.id);
163+
}
164+
136165
void _validateMonth(int month){
137166
if(month < 1 || month > 12){
138167
throw Exception('Month value: "$month" is not valid, Month must be between 1 and 12');

lib/domain/repository/user_money_repository.dart

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,22 @@ abstract class UserMoneyRepository {
99

1010
Future<double> getMonthExpense(int month, int year);
1111

12-
Future<List<TopSpendingCategory>> getTopSpendingCategoriesInMonth(
13-
{required int month,required int year, required int count});
12+
Future<List<TopSpendingCategory>> getTopSpendingCategoriesInMonth({
13+
required int month,
14+
required int year,
15+
required int count,
16+
});
1417

1518
Future<Currency> getCurrency();
1619

1720
Future<double> getSavingSpendingPercentage(int month, int year);
21+
22+
Future<double> getSalary();
23+
24+
Future<int> getSalaryDay();
25+
26+
Future<void> updateSalarySettings({
27+
required double salary,
28+
required int salaryDay,
29+
});
1830
}

lib/presentation/accout/screen/account_screen.dart

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import 'package:flutter/material.dart';
22
import 'package:flutter_bloc/flutter_bloc.dart';
3+
import 'package:moneyplus/presentation/navigation/routes.dart';
34
import 'package:moneyplus/app_prefernces_cubit.dart';
45
import 'package:moneyplus/presentation/accout/widget/theme_selection_dialog.dart';
56

@@ -126,6 +127,9 @@ class AccountScreen extends StatelessWidget {
126127
context,
127128
title: l10n.salarySettings,
128129
iconPath: AppAssets.iconMoney,
130+
onTap: () {
131+
EditSalaryRoute().push(context);
132+
},
129133
),
130134
accountSection(
131135
context,
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
import 'package:bloc/bloc.dart';
2+
import 'package:meta/meta.dart';
3+
import 'package:moneyplus/domain/repository/user_money_repository.dart';
4+
part 'salary_settings_state.dart';
5+
6+
class SalarySettingsCubit extends Cubit<SalarySettingsState> {
7+
SalarySettingsCubit({required this.userMoneyRepository}) : super(SalarySettingsLoading());
8+
9+
UserMoneyRepository userMoneyRepository;
10+
11+
void getData() async {
12+
try{
13+
final salary = await userMoneyRepository.getSalary();
14+
final salaryDay = await userMoneyRepository.getSalaryDay();
15+
emit(
16+
SalarySettingsLoaded(
17+
salary: salary.toString(),
18+
salaryDay: salaryDay.toString(),
19+
isSaveButtonEnabled: false,
20+
),
21+
);
22+
}catch(e){
23+
emit(SalarySettingsError(failure: SalarySettingsFailure.loadFailed));
24+
}
25+
_setButtonVisibility();
26+
}
27+
28+
void updateSalary(String salary) {
29+
if (state is SalarySettingsLoaded) {
30+
var currentState = state as SalarySettingsLoaded;
31+
emit(currentState.copyWith(salary: salary));
32+
_setButtonVisibility();
33+
}
34+
}
35+
36+
void updateSalaryDay(String salaryDay) {
37+
if (state is SalarySettingsLoaded) {
38+
var currentState = state as SalarySettingsLoaded;
39+
emit(currentState.copyWith(salaryDay: salaryDay));
40+
_setButtonVisibility();
41+
}
42+
}
43+
44+
Future<bool> saveChanges() async {
45+
try{
46+
if (state is SalarySettingsLoaded) {
47+
var currentState = state as SalarySettingsLoaded;
48+
await userMoneyRepository.updateSalarySettings(
49+
salary: double.parse(currentState.salary),
50+
salaryDay: int.parse(currentState.salaryDay),
51+
);
52+
}
53+
return true;
54+
}catch(e){
55+
return false;
56+
}
57+
58+
}
59+
60+
61+
62+
void _setButtonVisibility() {
63+
bool checkIfButtonShouldBeEnabled(SalarySettingsLoaded state) {
64+
final salary = double.tryParse(state.salary);
65+
if (salary == null) return false;
66+
final salaryDay = int.tryParse(state.salaryDay);
67+
if (salaryDay == null) return false;
68+
if(salaryDay < 1 || salaryDay > 31) return false;
69+
if(salary < 0) return false;
70+
return true;
71+
}
72+
73+
if (state is SalarySettingsLoaded) {
74+
var currentState = state as SalarySettingsLoaded;
75+
final shouldBeEnabled = checkIfButtonShouldBeEnabled(currentState);
76+
emit(currentState.copyWith(isButtonEnabled: shouldBeEnabled));
77+
}
78+
}
79+
}
80+
81+
enum SalarySettingsFailure {
82+
loadFailed,
83+
}

0 commit comments

Comments
 (0)