added cetak laporan

This commit is contained in:
kicap 2024-06-05 17:09:58 +08:00
parent 41ecbc0065
commit 0ad81dd67d
41 changed files with 3065 additions and 342 deletions

6
.env
View File

@ -1,6 +1,8 @@
url = 'https://panti-asuhan.s-keytech.com/'
api_url = 'https://panti-asuhan.s-keytech.com/api/'
# url = 'https://panti-asuhan.s-keytech.com/'
# api_url = 'https://panti-asuhan.s-keytech.com/api/'
# url = 'http://172.29.85.181/panti_asuhan2/'
# api_url = 'http://172.29.85.181/panti_asuhan2/api/'
# url = 'http://20.20.20.25/panti_asuhan2/'
# api_url = 'http://20.20.20.25/panti_asuhan2/api/'
url = 'https://localhost.kicap-karan.com/panti_asuhan/'
api_url = 'https://localhost.kicap-karan.com/panti_asuhan/api/'

View File

@ -1,26 +1,13 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.panti_asuhan">
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.panti_asuhan">
<uses-permission android:name="android.permission.INTERNET" />
<application
android:label="panti_asuhan"
android:name="${applicationName}"
android:icon="@mipmap/ic_launcher">
<activity
android:name=".MainActivity"
android:exported="true"
android:launchMode="singleTop"
android:theme="@style/LaunchTheme"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize">
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<application android:label="panti_asuhan" android:name="${applicationName}" android:icon="@mipmap/ic_launcher">
<activity android:name=".MainActivity" android:exported="true" android:launchMode="singleTop" android:theme="@style/LaunchTheme" android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode" android:hardwareAccelerated="true" android:windowSoftInputMode="adjustResize">
<!-- Specifies an Android theme to apply to this Activity as soon as
the Android process has started. This theme is visible to the user
while the Flutter UI initializes. After that, this theme continues
to determine the Window background behind the Flutter UI. -->
<meta-data
android:name="io.flutter.embedding.android.NormalTheme"
android:resource="@style/NormalTheme"
/>
<meta-data android:name="io.flutter.embedding.android.NormalTheme" android:resource="@style/NormalTheme" />
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
@ -28,8 +15,6 @@
</activity>
<!-- Don't delete the meta-data below.
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
<meta-data
android:name="flutterEmbedding"
android:value="2" />
<meta-data android:name="flutterEmbedding" android:value="2" />
</application>
</manifest>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 544 B

After

Width:  |  Height:  |  Size: 205 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 442 B

After

Width:  |  Height:  |  Size: 205 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 721 B

After

Width:  |  Height:  |  Size: 205 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 205 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 205 KiB

View File

@ -1,13 +1,16 @@
import 'package:panti_asuhan/ui/views/admin_index_tracking/edit_siswa/edit_dialog_siswa/edit_dialog_siswa_view.dart';
import 'package:stacked_services/stacked_services.dart';
import 'package:stacked/stacked_annotations.dart';
import '../services/http_services.dart';
import '../services/my_easyloading.dart';
import '../services/other_function.dart';
import '../ui/views/admin_index_tracking/add_siswa_dialog/add_siswa_dialog/add_siswa_dialog_view.dart';
import '../ui/views/admin_index_tracking/dana_sosial_khusus/add_donatur_dialog/add_donatur_dialog_view.dart';
import '../ui/views/admin_index_tracking/dana_sosial_khusus/dana_sosial_khusus_view.dart';
import '../ui/views/admin_index_tracking/admin_index_tracking_view.dart';
import '../ui/views/admin_index_tracking/dana_sosial_admin/dana_sosial_admin_view.dart';
import '../ui/views/admin_index_tracking/data_siswa/data_siswa_view.dart';
import '../ui/views/admin_index_tracking/edit_siswa/edit_dialog_siswa/edit_dialog_siswa_view.dart';
import '../ui/views/admin_index_tracking/edit_siswa/edit_siswa_view.dart';
import '../ui/views/admin_index_tracking/filter_dialog/filter_dialog_view.dart';
import '../ui/views/admin_index_tracking/profil/profil_view.dart';
@ -31,11 +34,14 @@ import '../ui/views/user_index_tracking/user_index_tracking_view.dart';
children: [
// MaterialRoute(page: AdminIndexView, initial: true),
MaterialRoute(page: DanaSosialAdminView),
MaterialRoute(page: DanaSosialKhususView),
MaterialRoute(page: DataSiswaView),
MaterialRoute(page: ProfilView),
MaterialRoute(page: VisiMisiView),
MaterialRoute(page: SejarahView),
MaterialRoute(page: StrukturOrganisasiView),
MaterialRoute(
page: StrukturOrganisasiView,
),
],
),
MaterialRoute(page: TambahDanaSosialView),
@ -46,6 +52,7 @@ import '../ui/views/user_index_tracking/user_index_tracking_view.dart';
children: [
// MaterialRoute(page: AdminIndexView, initial: true),
MaterialRoute(page: DanaSosialAdminView),
MaterialRoute(page: DanaSosialKhususView),
MaterialRoute(page: DataSiswaView),
MaterialRoute(page: ProfilView),
],
@ -55,6 +62,7 @@ import '../ui/views/user_index_tracking/user_index_tracking_view.dart';
children: [
// MaterialRoute(page: AdminIndexView, initial: true),
MaterialRoute(page: DanaSosialAdminView),
MaterialRoute(page: DanaSosialKhususView),
MaterialRoute(page: DataSiswaView),
MaterialRoute(page: ProfilView),
MaterialRoute(page: VisiMisiView),
@ -67,7 +75,8 @@ import '../ui/views/user_index_tracking/user_index_tracking_view.dart';
StackedDialog(classType: AddSiswaDialogView),
StackedDialog(classType: FilterDialogView),
StackedDialog(classType: EditStrukrurOrganisasiDialogView),
StackedDialog(classType: EditDialogSiswaView)
StackedDialog(classType: EditDialogSiswaView),
StackedDialog(classType: AddDonaturDialogView),
],
dependencies: [
LazySingleton(classType: NavigationService),
@ -78,6 +87,7 @@ import '../ui/views/user_index_tracking/user_index_tracking_view.dart';
LazySingleton(classType: MyEasyLoading),
LazySingleton(classType: MyHttpServices),
LazySingleton(classType: OtherFunction),
],
logger: StackedLogger(),
)

View File

@ -8,6 +8,7 @@ import 'package:stacked_services/stacked_services.dart';
import 'app.locator.dart';
import '../ui/views/admin_index_tracking/add_siswa_dialog/add_siswa_dialog/add_siswa_dialog_view.dart';
import '../ui/views/admin_index_tracking/dana_sosial_khusus/add_donatur_dialog/add_donatur_dialog_view.dart';
import '../ui/views/admin_index_tracking/edit_siswa/edit_dialog_siswa/edit_dialog_siswa_view.dart';
import '../ui/views/admin_index_tracking/filter_dialog/filter_dialog_view.dart';
import '../ui/views/admin_index_tracking/struktur_organisasi/edit_strukrur_organisasi_dialog/edit_strukrur_organisasi_dialog_view.dart';
@ -17,6 +18,7 @@ enum DialogType {
filterDialogView,
editStrukrurOrganisasiDialogView,
editDialogSiswaView,
addDonaturDialogView,
}
void setupDialogUi() {
@ -32,6 +34,8 @@ void setupDialogUi() {
request: request, completer: completer),
DialogType.editDialogSiswaView: (context, request, completer) =>
EditDialogSiswaView(request: request, completer: completer),
DialogType.addDonaturDialogView: (context, request, completer) =>
AddDonaturDialogView(request: request, completer: completer),
};
dialogService.registerCustomDialogBuilders(builders);

View File

@ -14,6 +14,7 @@ import 'package:stacked_shared/stacked_shared.dart';
import '../services/http_services.dart';
import '../services/my_easyloading.dart';
import '../services/other_function.dart';
final locator = StackedLocator.instance;
@ -32,4 +33,5 @@ Future<void> setupLocator({
locator.registerLazySingleton(() => BottomSheetService());
locator.registerLazySingleton(() => MyEasyLoading());
locator.registerLazySingleton(() => MyHttpServices());
locator.registerLazySingleton(() => OtherFunction());
}

View File

@ -11,18 +11,20 @@ import 'package:panti_asuhan/ui/views/admin_index_tracking/admin_index_tracking_
as _i4;
import 'package:panti_asuhan/ui/views/admin_index_tracking/dana_sosial_admin/dana_sosial_admin_view.dart'
as _i11;
import 'package:panti_asuhan/ui/views/admin_index_tracking/data_siswa/data_siswa_view.dart'
import 'package:panti_asuhan/ui/views/admin_index_tracking/dana_sosial_khusus/dana_sosial_khusus_view.dart'
as _i12;
import 'package:panti_asuhan/ui/views/admin_index_tracking/data_siswa/data_siswa_view.dart'
as _i13;
import 'package:panti_asuhan/ui/views/admin_index_tracking/edit_siswa/edit_siswa_view.dart'
as _i6;
import 'package:panti_asuhan/ui/views/admin_index_tracking/profil/profil_view.dart'
as _i13;
import 'package:panti_asuhan/ui/views/admin_index_tracking/sejarah/sejarah_view.dart'
as _i15;
import 'package:panti_asuhan/ui/views/admin_index_tracking/struktur_organisasi/struktur_organisasi_view.dart'
as _i16;
import 'package:panti_asuhan/ui/views/admin_index_tracking/visi_misi/visi_misi_view.dart'
as _i14;
import 'package:panti_asuhan/ui/views/admin_index_tracking/sejarah/sejarah_view.dart'
as _i16;
import 'package:panti_asuhan/ui/views/admin_index_tracking/struktur_organisasi/struktur_organisasi_view.dart'
as _i17;
import 'package:panti_asuhan/ui/views/admin_index_tracking/visi_misi/visi_misi_view.dart'
as _i15;
import 'package:panti_asuhan/ui/views/detail_dana_sosial/detail_dana_sosial_view.dart'
as _i7;
import 'package:panti_asuhan/ui/views/login_screen/login_screen_view.dart'
@ -36,7 +38,7 @@ import 'package:panti_asuhan/ui/views/tambah_dana_sosial/tambah_dana_sosial_view
import 'package:panti_asuhan/ui/views/user_index_tracking/user_index_tracking_view.dart'
as _i9;
import 'package:stacked/stacked.dart' as _i1;
import 'package:stacked_services/stacked_services.dart' as _i17;
import 'package:stacked_services/stacked_services.dart' as _i18;
class Routes {
static const splashScreenView = '/';
@ -126,8 +128,12 @@ class StackedRouter extends _i1.RouterBase {
);
},
_i5.TambahDanaSosialView: (data) {
final args = data.getArgs<TambahDanaSosialViewArguments>(
orElse: () => const TambahDanaSosialViewArguments(),
);
return _i10.MaterialPageRoute<dynamic>(
builder: (context) => const _i5.TambahDanaSosialView(),
builder: (context) =>
_i5.TambahDanaSosialView(key: args.key, isKhusus: args.isKhusus),
settings: data,
maintainState: false,
);
@ -144,8 +150,8 @@ class StackedRouter extends _i1.RouterBase {
_i7.DetailDanaSosialView: (data) {
final args = data.getArgs<DetailDanaSosialViewArguments>(nullOk: false);
return _i10.MaterialPageRoute<dynamic>(
builder: (context) =>
_i7.DetailDanaSosialView(key: args.key, id: args.id),
builder: (context) => _i7.DetailDanaSosialView(
key: args.key, id: args.id, isKhusus: args.isKhusus),
settings: data,
maintainState: false,
);
@ -172,6 +178,22 @@ class StackedRouter extends _i1.RouterBase {
Map<Type, _i1.StackedRouteFactory> get pagesMap => _pagesMap;
}
class TambahDanaSosialViewArguments {
const TambahDanaSosialViewArguments({
this.key,
this.isKhusus = false,
});
final _i10.Key? key;
final bool isKhusus;
@override
String toString() {
return '{"key": "$key", "isKhusus": "$isKhusus"}';
}
}
class EditSiswaViewArguments {
const EditSiswaViewArguments({
required this.idSiswa,
@ -192,21 +214,26 @@ class DetailDanaSosialViewArguments {
const DetailDanaSosialViewArguments({
this.key,
required this.id,
this.isKhusus = false,
});
final _i10.Key? key;
final int id;
final bool isKhusus;
@override
String toString() {
return '{"key": "$key", "id": "$id"}';
return '{"key": "$key", "id": "$id", "isKhusus": "$isKhusus"}';
}
}
class AdminIndexTrackingViewRoutes {
static const danaSosialAdminView = 'dana-sosial-admin-view';
static const danaSosialKhususView = 'dana-sosial-khusus-view';
static const dataSiswaView = 'data-siswa-view';
static const profilView = 'profil-view';
@ -219,6 +246,7 @@ class AdminIndexTrackingViewRoutes {
static const all = <String>{
danaSosialAdminView,
danaSosialKhususView,
dataSiswaView,
profilView,
visiMisiView,
@ -233,25 +261,29 @@ class AdminIndexTrackingViewRouter extends _i1.RouterBase {
AdminIndexTrackingViewRoutes.danaSosialAdminView,
page: _i11.DanaSosialAdminView,
),
_i1.RouteDef(
AdminIndexTrackingViewRoutes.danaSosialKhususView,
page: _i12.DanaSosialKhususView,
),
_i1.RouteDef(
AdminIndexTrackingViewRoutes.dataSiswaView,
page: _i12.DataSiswaView,
page: _i13.DataSiswaView,
),
_i1.RouteDef(
AdminIndexTrackingViewRoutes.profilView,
page: _i13.ProfilView,
page: _i14.ProfilView,
),
_i1.RouteDef(
AdminIndexTrackingViewRoutes.visiMisiView,
page: _i14.VisiMisiView,
page: _i15.VisiMisiView,
),
_i1.RouteDef(
AdminIndexTrackingViewRoutes.sejarahView,
page: _i15.SejarahView,
page: _i16.SejarahView,
),
_i1.RouteDef(
AdminIndexTrackingViewRoutes.strukturOrganisasiView,
page: _i16.StrukturOrganisasiView,
page: _i17.StrukturOrganisasiView,
),
];
@ -263,37 +295,44 @@ class AdminIndexTrackingViewRouter extends _i1.RouterBase {
maintainState: false,
);
},
_i12.DataSiswaView: (data) {
_i12.DanaSosialKhususView: (data) {
return _i10.MaterialPageRoute<dynamic>(
builder: (context) => const _i12.DataSiswaView(),
builder: (context) => const _i12.DanaSosialKhususView(),
settings: data,
maintainState: false,
);
},
_i13.ProfilView: (data) {
_i13.DataSiswaView: (data) {
return _i10.MaterialPageRoute<dynamic>(
builder: (context) => const _i13.ProfilView(),
builder: (context) => const _i13.DataSiswaView(),
settings: data,
maintainState: false,
);
},
_i14.VisiMisiView: (data) {
_i14.ProfilView: (data) {
return _i10.MaterialPageRoute<dynamic>(
builder: (context) => const _i14.VisiMisiView(),
builder: (context) => const _i14.ProfilView(),
settings: data,
maintainState: false,
);
},
_i15.SejarahView: (data) {
_i15.VisiMisiView: (data) {
return _i10.MaterialPageRoute<dynamic>(
builder: (context) => const _i15.SejarahView(),
builder: (context) => const _i15.VisiMisiView(),
settings: data,
maintainState: false,
);
},
_i16.StrukturOrganisasiView: (data) {
_i16.SejarahView: (data) {
return _i10.MaterialPageRoute<dynamic>(
builder: (context) => const _i16.StrukturOrganisasiView(),
builder: (context) => const _i16.SejarahView(),
settings: data,
maintainState: false,
);
},
_i17.StrukturOrganisasiView: (data) {
return _i10.MaterialPageRoute<dynamic>(
builder: (context) => const _i17.StrukturOrganisasiView(),
settings: data,
maintainState: false,
);
@ -309,12 +348,15 @@ class AdminIndexTrackingViewRouter extends _i1.RouterBase {
class PimpinanIndexTrackingViewRoutes {
static const danaSosialAdminView = 'dana-sosial-admin-view';
static const danaSosialKhususView = 'dana-sosial-khusus-view';
static const dataSiswaView = 'data-siswa-view';
static const profilView = 'profil-view';
static const all = <String>{
danaSosialAdminView,
danaSosialKhususView,
dataSiswaView,
profilView,
};
@ -326,13 +368,17 @@ class PimpinanIndexTrackingViewRouter extends _i1.RouterBase {
PimpinanIndexTrackingViewRoutes.danaSosialAdminView,
page: _i11.DanaSosialAdminView,
),
_i1.RouteDef(
PimpinanIndexTrackingViewRoutes.danaSosialKhususView,
page: _i12.DanaSosialKhususView,
),
_i1.RouteDef(
PimpinanIndexTrackingViewRoutes.dataSiswaView,
page: _i12.DataSiswaView,
page: _i13.DataSiswaView,
),
_i1.RouteDef(
PimpinanIndexTrackingViewRoutes.profilView,
page: _i13.ProfilView,
page: _i14.ProfilView,
),
];
@ -344,16 +390,23 @@ class PimpinanIndexTrackingViewRouter extends _i1.RouterBase {
maintainState: false,
);
},
_i12.DataSiswaView: (data) {
_i12.DanaSosialKhususView: (data) {
return _i10.MaterialPageRoute<dynamic>(
builder: (context) => const _i12.DataSiswaView(),
builder: (context) => const _i12.DanaSosialKhususView(),
settings: data,
maintainState: false,
);
},
_i13.ProfilView: (data) {
_i13.DataSiswaView: (data) {
return _i10.MaterialPageRoute<dynamic>(
builder: (context) => const _i13.ProfilView(),
builder: (context) => const _i13.DataSiswaView(),
settings: data,
maintainState: false,
);
},
_i14.ProfilView: (data) {
return _i10.MaterialPageRoute<dynamic>(
builder: (context) => const _i14.ProfilView(),
settings: data,
maintainState: false,
);
@ -369,6 +422,8 @@ class PimpinanIndexTrackingViewRouter extends _i1.RouterBase {
class UserIndexTrackingViewRoutes {
static const danaSosialAdminView = 'dana-sosial-admin-view';
static const danaSosialKhususView = 'dana-sosial-khusus-view';
static const dataSiswaView = 'data-siswa-view';
static const profilView = 'profil-view';
@ -381,6 +436,7 @@ class UserIndexTrackingViewRoutes {
static const all = <String>{
danaSosialAdminView,
danaSosialKhususView,
dataSiswaView,
profilView,
visiMisiView,
@ -395,25 +451,29 @@ class UserIndexTrackingViewRouter extends _i1.RouterBase {
UserIndexTrackingViewRoutes.danaSosialAdminView,
page: _i11.DanaSosialAdminView,
),
_i1.RouteDef(
UserIndexTrackingViewRoutes.danaSosialKhususView,
page: _i12.DanaSosialKhususView,
),
_i1.RouteDef(
UserIndexTrackingViewRoutes.dataSiswaView,
page: _i12.DataSiswaView,
page: _i13.DataSiswaView,
),
_i1.RouteDef(
UserIndexTrackingViewRoutes.profilView,
page: _i13.ProfilView,
page: _i14.ProfilView,
),
_i1.RouteDef(
UserIndexTrackingViewRoutes.visiMisiView,
page: _i14.VisiMisiView,
page: _i15.VisiMisiView,
),
_i1.RouteDef(
UserIndexTrackingViewRoutes.sejarahView,
page: _i15.SejarahView,
page: _i16.SejarahView,
),
_i1.RouteDef(
UserIndexTrackingViewRoutes.strukturOrganisasiView,
page: _i16.StrukturOrganisasiView,
page: _i17.StrukturOrganisasiView,
),
];
@ -425,37 +485,44 @@ class UserIndexTrackingViewRouter extends _i1.RouterBase {
maintainState: false,
);
},
_i12.DataSiswaView: (data) {
_i12.DanaSosialKhususView: (data) {
return _i10.MaterialPageRoute<dynamic>(
builder: (context) => const _i12.DataSiswaView(),
builder: (context) => const _i12.DanaSosialKhususView(),
settings: data,
maintainState: false,
);
},
_i13.ProfilView: (data) {
_i13.DataSiswaView: (data) {
return _i10.MaterialPageRoute<dynamic>(
builder: (context) => const _i13.ProfilView(),
builder: (context) => const _i13.DataSiswaView(),
settings: data,
maintainState: false,
);
},
_i14.VisiMisiView: (data) {
_i14.ProfilView: (data) {
return _i10.MaterialPageRoute<dynamic>(
builder: (context) => const _i14.VisiMisiView(),
builder: (context) => const _i14.ProfilView(),
settings: data,
maintainState: false,
);
},
_i15.SejarahView: (data) {
_i15.VisiMisiView: (data) {
return _i10.MaterialPageRoute<dynamic>(
builder: (context) => const _i15.SejarahView(),
builder: (context) => const _i15.VisiMisiView(),
settings: data,
maintainState: false,
);
},
_i16.StrukturOrganisasiView: (data) {
_i16.SejarahView: (data) {
return _i10.MaterialPageRoute<dynamic>(
builder: (context) => const _i16.StrukturOrganisasiView(),
builder: (context) => const _i16.SejarahView(),
settings: data,
maintainState: false,
);
},
_i17.StrukturOrganisasiView: (data) {
return _i10.MaterialPageRoute<dynamic>(
builder: (context) => const _i17.StrukturOrganisasiView(),
settings: data,
maintainState: false,
);
@ -468,7 +535,7 @@ class UserIndexTrackingViewRouter extends _i1.RouterBase {
Map<Type, _i1.StackedRouteFactory> get pagesMap => _pagesMap;
}
extension NavigatorStateExtension on _i17.NavigationService {
extension NavigatorStateExtension on _i18.NavigationService {
Future<dynamic> navigateToSplashScreenView([
int? routerId,
bool preventDuplicates = true,
@ -511,14 +578,17 @@ extension NavigatorStateExtension on _i17.NavigationService {
transition: transition);
}
Future<dynamic> navigateToTambahDanaSosialView([
Future<dynamic> navigateToTambahDanaSosialView({
_i10.Key? key,
bool isKhusus = false,
int? routerId,
bool preventDuplicates = true,
Map<String, String>? parameters,
Widget Function(BuildContext, Animation<double>, Animation<double>, Widget)?
transition,
]) async {
}) async {
return navigateTo<dynamic>(Routes.tambahDanaSosialView,
arguments: TambahDanaSosialViewArguments(key: key, isKhusus: isKhusus),
id: routerId,
preventDuplicates: preventDuplicates,
parameters: parameters,
@ -545,6 +615,7 @@ extension NavigatorStateExtension on _i17.NavigationService {
Future<dynamic> navigateToDetailDanaSosialView({
_i10.Key? key,
required int id,
bool isKhusus = false,
int? routerId,
bool preventDuplicates = true,
Map<String, String>? parameters,
@ -552,7 +623,8 @@ extension NavigatorStateExtension on _i17.NavigationService {
transition,
}) async {
return navigateTo<dynamic>(Routes.detailDanaSosialView,
arguments: DetailDanaSosialViewArguments(key: key, id: id),
arguments:
DetailDanaSosialViewArguments(key: key, id: id, isKhusus: isKhusus),
id: routerId,
preventDuplicates: preventDuplicates,
parameters: parameters,
@ -602,6 +674,22 @@ extension NavigatorStateExtension on _i17.NavigationService {
transition: transition);
}
Future<dynamic>
navigateToNestedDanaSosialKhususViewInAdminIndexTrackingViewRouter([
int? routerId,
bool preventDuplicates = true,
Map<String, String>? parameters,
Widget Function(BuildContext, Animation<double>, Animation<double>, Widget)?
transition,
]) async {
return navigateTo<dynamic>(
AdminIndexTrackingViewRoutes.danaSosialKhususView,
id: routerId,
preventDuplicates: preventDuplicates,
parameters: parameters,
transition: transition);
}
Future<dynamic> navigateToNestedDataSiswaViewInAdminIndexTrackingViewRouter([
int? routerId,
bool preventDuplicates = true,
@ -690,6 +778,22 @@ extension NavigatorStateExtension on _i17.NavigationService {
transition: transition);
}
Future<dynamic>
navigateToNestedDanaSosialKhususViewInPimpinanIndexTrackingViewRouter([
int? routerId,
bool preventDuplicates = true,
Map<String, String>? parameters,
Widget Function(BuildContext, Animation<double>, Animation<double>, Widget)?
transition,
]) async {
return navigateTo<dynamic>(
PimpinanIndexTrackingViewRoutes.danaSosialKhususView,
id: routerId,
preventDuplicates: preventDuplicates,
parameters: parameters,
transition: transition);
}
Future<dynamic>
navigateToNestedDataSiswaViewInPimpinanIndexTrackingViewRouter([
int? routerId,
@ -734,6 +838,21 @@ extension NavigatorStateExtension on _i17.NavigationService {
transition: transition);
}
Future<dynamic>
navigateToNestedDanaSosialKhususViewInUserIndexTrackingViewRouter([
int? routerId,
bool preventDuplicates = true,
Map<String, String>? parameters,
Widget Function(BuildContext, Animation<double>, Animation<double>, Widget)?
transition,
]) async {
return navigateTo<dynamic>(UserIndexTrackingViewRoutes.danaSosialKhususView,
id: routerId,
preventDuplicates: preventDuplicates,
parameters: parameters,
transition: transition);
}
Future<dynamic> navigateToNestedDataSiswaViewInUserIndexTrackingViewRouter([
int? routerId,
bool preventDuplicates = true,
@ -848,14 +967,17 @@ extension NavigatorStateExtension on _i17.NavigationService {
transition: transition);
}
Future<dynamic> replaceWithTambahDanaSosialView([
Future<dynamic> replaceWithTambahDanaSosialView({
_i10.Key? key,
bool isKhusus = false,
int? routerId,
bool preventDuplicates = true,
Map<String, String>? parameters,
Widget Function(BuildContext, Animation<double>, Animation<double>, Widget)?
transition,
]) async {
}) async {
return replaceWith<dynamic>(Routes.tambahDanaSosialView,
arguments: TambahDanaSosialViewArguments(key: key, isKhusus: isKhusus),
id: routerId,
preventDuplicates: preventDuplicates,
parameters: parameters,
@ -882,6 +1004,7 @@ extension NavigatorStateExtension on _i17.NavigationService {
Future<dynamic> replaceWithDetailDanaSosialView({
_i10.Key? key,
required int id,
bool isKhusus = false,
int? routerId,
bool preventDuplicates = true,
Map<String, String>? parameters,
@ -889,7 +1012,8 @@ extension NavigatorStateExtension on _i17.NavigationService {
transition,
}) async {
return replaceWith<dynamic>(Routes.detailDanaSosialView,
arguments: DetailDanaSosialViewArguments(key: key, id: id),
arguments:
DetailDanaSosialViewArguments(key: key, id: id, isKhusus: isKhusus),
id: routerId,
preventDuplicates: preventDuplicates,
parameters: parameters,
@ -940,6 +1064,22 @@ extension NavigatorStateExtension on _i17.NavigationService {
transition: transition);
}
Future<dynamic>
replaceWithNestedDanaSosialKhususViewInAdminIndexTrackingViewRouter([
int? routerId,
bool preventDuplicates = true,
Map<String, String>? parameters,
Widget Function(BuildContext, Animation<double>, Animation<double>, Widget)?
transition,
]) async {
return replaceWith<dynamic>(
AdminIndexTrackingViewRoutes.danaSosialKhususView,
id: routerId,
preventDuplicates: preventDuplicates,
parameters: parameters,
transition: transition);
}
Future<dynamic> replaceWithNestedDataSiswaViewInAdminIndexTrackingViewRouter([
int? routerId,
bool preventDuplicates = true,
@ -1028,6 +1168,22 @@ extension NavigatorStateExtension on _i17.NavigationService {
transition: transition);
}
Future<dynamic>
replaceWithNestedDanaSosialKhususViewInPimpinanIndexTrackingViewRouter([
int? routerId,
bool preventDuplicates = true,
Map<String, String>? parameters,
Widget Function(BuildContext, Animation<double>, Animation<double>, Widget)?
transition,
]) async {
return replaceWith<dynamic>(
PimpinanIndexTrackingViewRoutes.danaSosialKhususView,
id: routerId,
preventDuplicates: preventDuplicates,
parameters: parameters,
transition: transition);
}
Future<dynamic>
replaceWithNestedDataSiswaViewInPimpinanIndexTrackingViewRouter([
int? routerId,
@ -1072,6 +1228,22 @@ extension NavigatorStateExtension on _i17.NavigationService {
transition: transition);
}
Future<dynamic>
replaceWithNestedDanaSosialKhususViewInUserIndexTrackingViewRouter([
int? routerId,
bool preventDuplicates = true,
Map<String, String>? parameters,
Widget Function(BuildContext, Animation<double>, Animation<double>, Widget)?
transition,
]) async {
return replaceWith<dynamic>(
UserIndexTrackingViewRoutes.danaSosialKhususView,
id: routerId,
preventDuplicates: preventDuplicates,
parameters: parameters,
transition: transition);
}
Future<dynamic> replaceWithNestedDataSiswaViewInUserIndexTrackingViewRouter([
int? routerId,
bool preventDuplicates = true,

View File

@ -2,6 +2,7 @@ import 'package:shared_preferences/shared_preferences.dart';
import 'package:stacked/stacked.dart';
import 'package:stacked_services/stacked_services.dart';
import '../../services/other_function.dart';
import '../app.locator.dart';
class CustomBaseViewModel extends BaseViewModel {
@ -10,6 +11,7 @@ class CustomBaseViewModel extends BaseViewModel {
final bottomSheetService = locator<BottomSheetService>();
final snackbarService = locator<SnackbarService>();
final Future<SharedPreferences> prefs = SharedPreferences.getInstance();
final otherFunction = locator<OtherFunction>();
void back() {
navigationService.back();

View File

@ -1,3 +1,5 @@
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:flutter_easyloading/flutter_easyloading.dart';
@ -10,6 +12,7 @@ import 'app/themes/app_theme.dart';
Future main() async {
WidgetsFlutterBinding.ensureInitialized();
HttpOverrides.global = MyHttpOverrides();
await dotenv.load(fileName: ".env");
await setupAllLocator();
runApp(const MyApp());
@ -38,3 +41,12 @@ Future<void> setupAllLocator() async {
// setupBottomsheetUi();
// setupSnackbarUi();
}
class MyHttpOverrides extends HttpOverrides {
@override
HttpClient createHttpClient(SecurityContext? context) {
return super.createHttpClient(context)
..badCertificateCallback =
(X509Certificate cert, String host, int port) => true;
}
}

View File

@ -7,6 +7,9 @@ class DanaSosialModel {
String? keterangan;
String? jenisDonasi;
String? status;
String? jenisBarang;
String? satuan;
String? jumlahBarang;
String? createdAt;
String? updatedAt;
@ -20,6 +23,9 @@ class DanaSosialModel {
this.keterangan,
this.jenisDonasi,
this.status,
this.jenisBarang,
this.satuan,
this.jumlahBarang,
this.createdAt,
this.updatedAt});
@ -33,6 +39,9 @@ class DanaSosialModel {
jenisDonasi = json['jenis'];
status =
json['status'] == '0' ? 'Belum Dikonfirmasi' : 'Sudah Dikonfirmasi';
jenisBarang = json['jenis_barang'] ?? '';
satuan = json['satuan'] ?? '';
jumlahBarang = json['jumlah_barang'] ?? '';
createdAt = json['created_at'];
updatedAt = json['updated_at'];
}
@ -47,6 +56,9 @@ class DanaSosialModel {
data['ket'] = keterangan;
data['jenis'] = jenisDonasi;
data['status'] = status;
data['jenis_barang'] = jenisBarang;
data['satuan'] = satuan;
data['jumlah_barang'] = jumlahBarang;
data['created_at'] = createdAt;
data['updated_at'] = updatedAt;
return data;

View File

@ -32,7 +32,8 @@ class MyHttpServices {
return await _dio.post(path, data: formData);
} on DioError catch (e) {
log.e(e.message);
log.e(e.response);
log.e(e.response!.statusCode);
log.e(e.response!.statusMessage);
rethrow;
}
}

View File

@ -46,4 +46,61 @@ class OtherFunction {
return '';
}
}
String changeMonthYear(String s) {
// get the last 2 digits
String month = s.substring(s.length - 2);
// get the first 4 digits
String year = s.substring(0, 4);
// return the month and year
switch (month) {
case '01':
return 'Januari $year';
case '02':
return 'Februari $year';
case '03':
return 'Maret $year';
case '04':
return 'April $year';
case '05':
return 'Mei $year';
case '06':
return 'Juni $year';
case '07':
return 'Juli $year';
case '08':
return 'Agustus $year';
case '09':
return 'September $year';
case '10':
return 'Oktober $year';
case '11':
return 'November $year';
case '12':
return 'Desember $year';
default:
return '';
}
}
String getDayOfWeek(String date) {
DateTime dateTime = DateTime.parse(date);
List<String> daysOfWeek = [
'Senin',
'Selasa',
'Rabu',
'Kamis',
'Jumat',
'Sabtu',
'Minggu'
];
return daysOfWeek[dateTime.weekday - 1];
}
String capitalizeEachWord(String s) {
return s
.split(' ')
.map((word) => word[0].toUpperCase() + word.substring(1))
.join(' ');
}
}

View File

@ -53,7 +53,7 @@ class AddSiswaDialogView extends StatelessWidget {
mainAxisSize: MainAxisSize.min,
children: [
Text(
'Tambah Siswa',
'Tambah Anak Panti',
style: boldTextStyle.copyWith(
fontSize: 16,
),

View File

@ -67,12 +67,13 @@ class AdminIndexTrackingView extends StatelessWidget {
? sixthGrey
: backgroundColor),
title: Text(
item['name'],
model.otherFunction.capitalizeEachWord(item['name']),
style: regularTextStyle.copyWith(
color: model.currentIndex ==
model.bottomNavBarList.indexOf(item)
? sixthGrey
: Colors.grey,
overflow: TextOverflow.ellipsis,
),
),
backgroundColor: model.currentIndex ==

View File

@ -1,4 +1,5 @@
import 'package:flutter/material.dart';
import 'package:panti_asuhan/services/other_function.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:stacked/stacked.dart';
import 'package:stacked_services/stacked_services.dart';
@ -12,14 +13,16 @@ class AdminIndexTrackingViewModel extends IndexTrackingViewModel {
final _navigationService = locator<NavigationService>();
final _dialogService = locator<DialogService>();
final Future<SharedPreferences> _prefs = SharedPreferences.getInstance();
final otherFunction = locator<OtherFunction>();
final _bottomNavBarList = [
{
'name': 'Siswa',
'name': 'List',
'icon': Icons.people_alt_outlined,
'header': 'List Siswa'
'header': 'List Anak Panti'
},
{'name': 'Dana', 'icon': Icons.money, 'header': 'Dana Sosial'},
// {'name': 'Dana', 'icon': Icons.money, 'header': 'Dana Sosial Khusus'},
{
'name': 'Profil',
'icon': Icons.person_4_outlined,
@ -39,6 +42,7 @@ class AdminIndexTrackingViewModel extends IndexTrackingViewModel {
final List<String> _views = [
AdminIndexTrackingViewRoutes.dataSiswaView,
AdminIndexTrackingViewRoutes.danaSosialAdminView,
// AdminIndexTrackingViewRoutes.danaSosialKhususView,
AdminIndexTrackingViewRoutes.profilView,
AdminIndexTrackingViewRoutes.visiMisiView,
AdminIndexTrackingViewRoutes.sejarahView,

View File

@ -22,86 +22,18 @@ class DanaSosialAdminView extends StatelessWidget {
Widget? child,
) {
return Scaffold(
body: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: Container(
padding: const EdgeInsets.symmetric(
horizontal: 15, vertical: 10),
width: double.infinity,
decoration: BoxDecoration(
color: mainColor,
borderRadius: BorderRadius.circular(10),
boxShadow: [
BoxShadow(
color: mainGrey.withOpacity(0.5),
spreadRadius: 5,
blurRadius: 7,
offset: const Offset(
0, 3), // changes position of shadow
),
],
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Dana Sosial Bulan Ini',
style: boldTextStyle.copyWith(
color: Colors.white,
fontSize: 20,
),
),
const SizedBox(height: 10),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'Total Dana Sosial',
style: regularTextStyle.copyWith(
color: Colors.white,
fontSize: 15,
),
),
Text(
'Rp. ${OtherFunction().commaFormat(model.jumlahDonasi)}',
style: regularTextStyle.copyWith(
color: Colors.white,
fontSize: 15,
),
),
],
),
],
),
),
),
const SizedBox(width: 10),
Container(
width: 50,
height: 50,
decoration: const BoxDecoration(
shape: BoxShape.circle,
color: mainColor,
),
child: IconButton(
icon: const Icon(
Icons.filter_list,
color: Colors.white,
),
onPressed: () {
model.filterDialog(context);
},
),
),
],
),
const SizedBox(height: 25),
Expanded(
child: Container(
body: SingleChildScrollView(
child: Column(
children: [
const SizedBox(height: 10),
Text(
"Laporan Harian",
style:
boldTextStyle.copyWith(fontSize: 15, color: Colors.black),
),
Container(
padding: const EdgeInsets.all(10),
height: MediaQuery.of(context).size.height * 0.45,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(10),
@ -124,25 +56,384 @@ class DanaSosialAdminView extends StatelessWidget {
),
),
)
: const TheData(),
: const TheDataNewly(),
),
),
],
const SizedBox(
height: 30,
),
Text(
"Laporan Bulanan",
style:
boldTextStyle.copyWith(fontSize: 15, color: Colors.black),
),
Container(
padding: const EdgeInsets.all(15),
width: double.infinity,
height: MediaQuery.of(context).size.height * 0.25,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(10),
boxShadow: [
BoxShadow(
color: mainGrey.withOpacity(0.5),
spreadRadius: 5,
blurRadius: 7,
offset:
const Offset(0, 3), // changes position of shadow
),
],
),
child: model.monthIncomeOutcome.isEmpty
? const Center(
child: Text(
'Tidak ada data',
))
: const HasilIncomeOutcome(),
),
const SizedBox(
height: 30,
),
Text(
"Laporan Tahunan",
style:
boldTextStyle.copyWith(fontSize: 15, color: Colors.black),
),
Container(
padding: const EdgeInsets.all(15),
width: double.infinity,
height: MediaQuery.of(context).size.height * 0.25,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(10),
boxShadow: [
BoxShadow(
color: mainGrey.withOpacity(0.5),
spreadRadius: 5,
blurRadius: 7,
offset:
const Offset(0, 3), // changes position of shadow
),
],
),
child: model.yearIncomeOutcome.isNotEmpty
? const TahunanWidget()
: const Center(
child: Text(
'Tidak ada data',
),
),
),
const SizedBox(
height: 30,
),
Container(
padding: const EdgeInsets.all(20),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(10),
boxShadow: [
BoxShadow(
color: mainGrey.withOpacity(0.5),
spreadRadius: 5,
blurRadius: 7,
offset:
const Offset(0, 3), // changes position of shadow
),
],
),
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
const Text(
'Total Pemasukan :',
),
const Expanded(child: SizedBox()),
Text(
'Rp. ${OtherFunction().commaFormat(model.totalIncome)}',
)
],
),
const SizedBox(height: 10),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
const Text(
'Total Pengeluaran :',
),
const Expanded(child: SizedBox()),
Text(
'Rp. ${OtherFunction().commaFormat(model.totalOutcome)}',
)
],
),
],
),
),
const SizedBox(
height: 30,
),
],
),
),
floatingActionButton: model.role == 'admin'
? FloatingActionButton(
floatingActionButton: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
if (model.role == 'admin')
FloatingActionButton(
mini: true,
heroTag: 'btn11',
onPressed: () {
model.goToTambahDanaSosial();
},
child: const Icon(Icons.add),
)
: null,
),
const SizedBox(width: 5),
FloatingActionButton(
mini: true,
heroTag: 'btn22',
onPressed: () {
model.filterDialog(context);
},
child: const Icon(Icons.filter_list),
),
],
),
floatingActionButtonLocation: FloatingActionButtonLocation.miniEndTop,
);
},
);
}
}
class TahunanWidget extends ViewModelWidget<DanaSosialAdminViewModel> {
const TahunanWidget({
super.key,
});
@override
Widget build(BuildContext context, DanaSosialAdminViewModel viewModel) {
return SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
for (int i = 0; i < viewModel.yearIncomeOutcome.length; i++)
Column(
mainAxisSize: MainAxisSize.min,
children: [
Align(
alignment: Alignment.centerLeft,
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Text(
"Tahun ${viewModel.yearIncomeOutcome[i]['tahun']}",
style: boldTextStyle.copyWith(
decoration: TextDecoration.underline,
fontSize: 17,
),
),
const SizedBox(
width: 10,
),
if (viewModel.role == 'admin' ||
viewModel.role == 'pimpinan')
Container(
alignment: Alignment.center,
width: 30,
height: 30,
decoration: BoxDecoration(
color: mainColor,
borderRadius: BorderRadius.circular(50),
),
child: IconButton(
onPressed: () async {
// sini untuk laporan bulanan
await viewModel.goToLaporanTahunan(
viewModel.yearIncomeOutcome[i]['tahun']);
},
icon: const Icon(
Icons.list_alt_outlined,
color: Colors.white,
size: 15,
),
),
)
],
),
),
const SizedBox(
height: 5,
),
Table(
border: TableBorder.all(
color: Colors.grey,
),
children: [
const TableRow(children: [
TableCell(
child: Center(
child: Text(
'Pemasukan',
style: boldTextStyle,
))),
TableCell(
child: Center(
child: Text(
'Pengeluaran',
style: boldTextStyle,
)))
]),
TableRow(children: [
TableCell(
child: Center(
child: Text(
'Rp. ${OtherFunction().commaFormat(viewModel.yearIncomeOutcome[i]['pemasukan'])}',
style: italicTextStyle,
))),
TableCell(
child: Center(
child: Text(
'Rp. ${OtherFunction().commaFormat(viewModel.yearIncomeOutcome[i]['pengeluaran'])}',
style: italicTextStyle,
)))
]),
],
),
const SizedBox(
height: 5,
),
const Divider(
color: Colors.grey,
thickness: 1,
),
const SizedBox(
height: 5,
),
],
)
],
),
);
}
}
class HasilIncomeOutcome extends ViewModelWidget<DanaSosialAdminViewModel> {
const HasilIncomeOutcome({
super.key,
});
@override
Widget build(BuildContext context, DanaSosialAdminViewModel viewModel) {
return SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
for (int i = 0; i < viewModel.monthIncomeOutcome.length; i++)
Column(
mainAxisSize: MainAxisSize.min,
children: [
Align(
alignment: Alignment.centerLeft,
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Text(
viewModel.otherFunction.changeMonthYear(
viewModel.monthIncomeOutcome[i]['month']),
style: boldTextStyle.copyWith(
decoration: TextDecoration.underline,
fontSize: 17,
),
),
const SizedBox(
width: 10,
),
if (viewModel.role == 'admin' ||
viewModel.role == 'pimpinan')
Container(
alignment: Alignment.center,
width: 30,
height: 30,
decoration: BoxDecoration(
color: mainColor,
borderRadius: BorderRadius.circular(50),
),
child: IconButton(
onPressed: () async {
// sini untuk laporan bulanan
await viewModel.goToLaporanBulanan(
viewModel.monthIncomeOutcome[i]['month']);
},
icon: const Icon(
Icons.list_alt_outlined,
color: Colors.white,
size: 15,
),
),
)
],
),
),
const SizedBox(
height: 5,
),
Table(
border: TableBorder.all(
color: Colors.grey,
),
children: [
const TableRow(children: [
TableCell(
child: Center(
child: Text(
'Pemasukan',
style: boldTextStyle,
))),
TableCell(
child: Center(
child: Text(
'Pengeluaran',
style: boldTextStyle,
)))
]),
TableRow(children: [
TableCell(
child: Center(
child: Text(
'Rp. ${OtherFunction().commaFormat(viewModel.monthIncomeOutcome[i]['income'])}',
style: italicTextStyle,
))),
TableCell(
child: Center(
child: Text(
'Rp. ${OtherFunction().commaFormat(viewModel.monthIncomeOutcome[i]['outcome'])}',
style: italicTextStyle,
)))
]),
],
),
const SizedBox(
height: 5,
),
const Divider(
color: Colors.grey,
thickness: 1,
),
const SizedBox(
height: 5,
),
],
)
],
),
);
}
}
class TheData extends ViewModelWidget<DanaSosialAdminViewModel> {
const TheData({
super.key,
@ -154,6 +445,8 @@ class TheData extends ViewModelWidget<DanaSosialAdminViewModel> {
padding: const EdgeInsets.symmetric(horizontal: 15, vertical: 10),
itemCount: viewModel.danaSosialModelList.length,
itemBuilder: (context, index) {
// viewModel.log.i(viewModel.danaSosialModelList[index].tanggal);
String jumlahDonasi = viewModel
.danaSosialModelList[index].jenisDonasi !=
'Barang'
@ -278,3 +571,329 @@ class TheData extends ViewModelWidget<DanaSosialAdminViewModel> {
);
}
}
class TheDataNewly extends ViewModelWidget<DanaSosialAdminViewModel> {
const TheDataNewly({
super.key,
});
@override
Widget build(BuildContext context, DanaSosialAdminViewModel viewModel) {
return ListView.builder(
itemCount: viewModel.filteredByDateData.length,
itemBuilder: (context, index) {
return Padding(
padding: const EdgeInsets.only(bottom: 30),
child: Container(
padding: const EdgeInsets.all(5),
decoration: const BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(10)),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'${viewModel.otherFunction.changeMonthYear(viewModel.filteredByDateData[index]['month'])} ',
style: boldTextStyle.copyWith(
decoration: TextDecoration.underline,
fontSize: 17,
),
),
const SizedBox(height: 10),
for (int i = 0;
i < viewModel.filteredByDateData[index]['data'].length;
i++)
Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
Row(
mainAxisSize: MainAxisSize.min,
children: [
Text(
'${viewModel.filteredByDateData[index]['data'][i]['date']} : ${viewModel.otherFunction.getDayOfWeek(viewModel.filteredByDateData[index]['data'][i]['date'])}',
style: italicTextStyle.copyWith(
fontWeight: FontWeight.bold, fontSize: 15),
),
const SizedBox(
width: 10,
),
if (viewModel.role == 'admin' ||
viewModel.role == 'pimpinan')
Container(
alignment: Alignment.center,
width: 35,
height: 35,
decoration: BoxDecoration(
color: mainColor,
borderRadius: BorderRadius.circular(35),
),
child: IconButton(
onPressed: () {
viewModel.getLaporanHarian(
viewModel.filteredByDateData[index]
['data'][i]['date'],
viewModel.otherFunction.getDayOfWeek(
viewModel.filteredByDateData[index]
['data'][i]['date']));
},
icon: const Icon(
Icons.list_alt_outlined,
color: Colors.white,
size: 20,
),
),
)
],
),
const SizedBox(
height: 10,
),
Table(
border: TableBorder.all(
color: Colors.grey,
),
columnWidths: viewModel.role == 'admin'
? const {
0: FlexColumnWidth(
1), // 1/3 of the available width
1: FlexColumnWidth(
1.5), // 2/3 of the available width
2: FlexColumnWidth(
2.5), // 2/3 of the available width
3: FlexColumnWidth(
3), // 2/3 of the available width
4: FlexColumnWidth(
2), // 2/3 of the available width
}
: const {
0: FlexColumnWidth(
1), // 1/3 of the available width
1: FlexColumnWidth(
2), // 2/3 of the available width
2: FlexColumnWidth(
2), // 2/3 of the available width
3: FlexColumnWidth(
3), // 2/3 of the available width
},
children: [
TableRow(
children: [
const TableCell(
child: Center(
child: Text(
'No',
style: boldTextStyle,
),
),
),
const TableCell(
child: Center(
child: Text(
'Jenis',
style: boldTextStyle,
))),
const TableCell(
child: Center(
child: Text(
'Donatur',
style: boldTextStyle,
))),
const TableCell(
child: Center(
child: Text(
'Jumlah /\nKeterangan',
style: boldTextStyle,
),
),
),
if (viewModel.role == 'admin')
const TableCell(
child: Center(
child: Text(
'Aksi',
style: boldTextStyle,
),
),
)
],
),
for (int j = 0;
j <
viewModel
.filteredByDateData[index]['data'][i]
['data_dana']
.length;
j++)
TableRow(
children: [
TableCell(
child: Padding(
padding: const EdgeInsets.symmetric(
vertical: 4,
horizontal: 4,
),
child: Center(
child: Text(
'${j + 1}',
style: regularTextStyle,
),
),
),
),
TableCell(
child: Padding(
padding: const EdgeInsets.symmetric(
vertical: 4,
horizontal: 4,
),
child: Center(
// circle icon
child: viewModel
.filteredByDateData[index]
['data'][i]['data_dana']
[j]
.bentuk ==
'Pemasukan'
? const JenisIconContainer(
color: Colors.green,
icon: Icons.arrow_upward,
)
: const JenisIconContainer(
color: Colors.red,
icon: Icons.arrow_downward,
)),
),
),
TableCell(
child: Padding(
padding: const EdgeInsets.symmetric(
vertical: 4,
horizontal: 4,
),
child: Center(
child: Text(
'${viewModel.filteredByDateData[index]['data'][i]['data_dana'][j].nama == '' ? '-' : viewModel.filteredByDateData[index]['data'][i]['data_dana'][j].nama}',
style: regularTextStyle,
)),
)),
TableCell(
child: Padding(
padding: const EdgeInsets.symmetric(
vertical: 4,
horizontal: 4,
),
child: Center(
child: Text(
viewModel
.filteredByDateData[index]
['data'][i]['data_dana']
[j]
.jenisDonasi ==
'Uang'
? 'Rp. ${viewModel.otherFunction.commaFormat(int.parse(viewModel.filteredByDateData[index]['data'][i]['data_dana'][j].jumlah))}'
: viewModel
.filteredByDateData[index]
['data'][i]['data_dana'][j]
.keterangan,
style: regularTextStyle,
),
),
),
),
if (viewModel.role == 'admin')
TableCell(
child: Center(
child: Padding(
padding: const EdgeInsets.symmetric(
vertical: 4,
horizontal: 4,
),
child: Wrap(
spacing: 5,
runSpacing: 10,
children: [
GestureDetector(
onTap: () {
viewModel.goToEditDanaSosial(
int.parse(viewModel
.filteredByDateData[
index]['data'][i]
['data_dana'][j]
.idDanaSosial));
},
child: JenisIconContainer(
color: Colors.blue[600]!,
icon: Icons.edit,
),
),
GestureDetector(
onTap: () {
viewModel.deleteData(
int.parse(viewModel
.filteredByDateData[index]
['data'][i]
['data_dana'][j]
.idDanaSosial!),
);
},
child: const JenisIconContainer(
color: Colors.red,
icon: Icons.delete,
),
),
],
),
),
),
)
],
),
],
),
const SizedBox(height: 10),
// create a horizontal line
const Divider(
color: Colors.grey,
thickness: 1.0,
),
const SizedBox(height: 10),
],
),
],
),
),
);
},
);
}
}
class JenisIconContainer extends StatelessWidget {
const JenisIconContainer({
super.key,
required this.color,
required this.icon,
});
final Color color;
final IconData icon;
@override
Widget build(BuildContext context) {
return Container(
width: 20,
height: 20,
alignment: Alignment.center,
decoration: BoxDecoration(
color: color,
shape: BoxShape.circle,
),
child: Icon(
icon,
color: Colors.white,
size: 15,
),
);
}
}

View File

@ -1,5 +1,7 @@
import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:flutter_file_downloader/flutter_file_downloader.dart';
import 'package:shared_preferences/shared_preferences.dart';
import '../../../../app/app.dialogs.dart';
@ -16,15 +18,23 @@ class DanaSosialAdminViewModel extends CustomBaseViewModel {
final log = getLogger('DanaSosialAdminViewModel');
final _httpService = locator<MyHttpServices>();
final easyLoading = locator<MyEasyLoading>();
// final otherF
String url = dotenv.env['url']!;
int bulan = DateTime.now().month;
List<DanaSosialModel> danaSosialModelList = [];
List<Map<String, dynamic>> filteredByDateData = []; // newly added
List<Map<String, dynamic>> monthIncomeOutcome = []; // newly added
List<Map<String, dynamic>> yearIncomeOutcome = []; // newly added
int totalIncome = 0; // newly added
int totalOutcome = 0; // newly added
String? role;
bool? isLogin;
int jumlahDonasi = 0;
int jumlahPengeluaran = 0;
Future<void> init() async {
await getData();
@ -41,15 +51,16 @@ class DanaSosialAdminViewModel extends CustomBaseViewModel {
easyLoading.showLoading();
// get the month
var bulan = DateTime.now().month;
log.i(bulan);
// log.i(bulan);
// change bulan to string and add 0 if it is less than 10
String bulanString = bulan.toString().length == 1 ? '0$bulan' : '$bulan';
log.i(bulanString);
// log.i(bulanString);
try {
var response = await _httpService.get('pemasukan?bulan=$bulanString');
log.i(response.data['jumlah']);
// log.i(response.data['jumlah']);
// var theJumlahDonasi = response.data['jumlah'];
jumlahDonasi = response.data['jumlah'];
jumlahPengeluaran = response.data['jumlah_pengeluaran'];
} catch (e) {
log.e(e);
} finally {
@ -74,17 +85,110 @@ class DanaSosialAdminViewModel extends CustomBaseViewModel {
}
}
setBusy(false);
changeByDate(danaSosialModelList);
getTahunan();
notifyListeners();
log.i(danaSosialModelList);
// log.i(danaSosialModelList.length);
} catch (e) {
log.e(e);
setBusy(false);
} finally {
setBusy(false);
easyLoading.dismissLoading();
}
}
getTahunan() async {
try {
var response = await _httpService.get('data_tahunan');
var datanya = response.data['data'];
log.i(datanya.length);
for (int i = 0; i < datanya.length; i++) {
log.i(datanya[i]);
yearIncomeOutcome.add(datanya[i]);
}
notifyListeners();
} catch (e) {
log.e(e);
}
}
//newly added
changeByDate(List<DanaSosialModel> data) {
filteredByDateData = [];
for (var item in data) {
var monthKey =
item.tanggal!.substring(0, 7); // Extracting the year and month
var dateKey = item.tanggal; // The full date
var monthData = filteredByDateData.firstWhere(
(element) => element['month'] == monthKey,
orElse: () => {
'month': monthKey,
'data': [],
});
var dateData =
monthData['data'].firstWhere((element) => element['date'] == dateKey,
orElse: () => {
'date': dateKey,
'data_dana': [],
});
dateData['data_dana'].add(item);
if (!monthData['data'].contains(dateData)) {
monthData['data'].add(dateData);
}
if (!filteredByDateData.contains(monthData)) {
filteredByDateData.add(monthData);
}
}
filteredByDateData.sort((a, b) => a['month'].compareTo(b['month']));
// log.i(filteredByDateData);
// group the data by month
monthIncomeOutcome = [];
for (var item in filteredByDateData) {
var income = 0;
var outcome = 0;
for (var dateData in item['data']) {
for (var danaSosialModel in dateData['data_dana']) {
if (danaSosialModel.bentuk == 'Pemasukan' &&
danaSosialModel.jenisDonasi == 'Uang') {
income += int.parse(danaSosialModel.jumlah ?? '0');
} else if (danaSosialModel.bentuk == 'Pengeluaran' &&
danaSosialModel.jenisDonasi == 'Uang') {
outcome += int.parse(danaSosialModel.jumlah ?? '0');
}
}
}
monthIncomeOutcome.add({
'month': item['month'],
'income': income,
'outcome': outcome,
});
}
// log.i(monthIncomeOutcome);
totalIncome = 0;
totalOutcome = 0;
for (var item in monthIncomeOutcome) {
totalIncome += int.parse(item['income'].toString());
totalOutcome += int.parse(item['outcome'].toString());
}
log.i(totalIncome);
log.i(totalOutcome);
}
goToTambahDanaSosial() {
navigationService.navigateTo(Routes.tambahDanaSosialView);
}
@ -104,6 +208,8 @@ class DanaSosialAdminViewModel extends CustomBaseViewModel {
danaSosialModelList = [];
var datanya = response.data['data'];
jumlahDonasi = response.data['jumlah_donasi'];
jumlahPengeluaran = response.data['jumlah_pengeluaran'];
// log.i(datanya.length);
if (datanya.length > 0) {
for (var item in datanya) {
@ -112,8 +218,9 @@ class DanaSosialAdminViewModel extends CustomBaseViewModel {
}
setBusy(false);
changeByDate(danaSosialModelList);
notifyListeners();
log.i(danaSosialModelList);
// log.i(danaSosialModelList);
} catch (e) {
log.e(e);
setBusy(false);
@ -163,7 +270,7 @@ class DanaSosialAdminViewModel extends CustomBaseViewModel {
sql = sql.substring(0, sql.length - 4);
}
log.i(sql);
// log.i(sql);
getFilter(sql);
}
@ -194,12 +301,12 @@ class DanaSosialAdminViewModel extends CustomBaseViewModel {
easyLoading.showLoading();
setBusy(true);
try {
var response = await _httpService.postWithFormData(
await _httpService.postWithFormData(
'hapus_dana_sosial',
FormData.fromMap({
'id_dana_sosial': parse,
}));
log.i(response.data);
// log.i(response.data);
easyLoading.dismissLoading();
easyLoading.showSuccess('Data berhasil dihapus');
getData();
@ -213,10 +320,152 @@ class DanaSosialAdminViewModel extends CustomBaseViewModel {
easyLoading.dismissLoading();
}
} else {
log.i('cancel');
// log.i('cancel');
return;
}
},
);
}
goToLaporanBulanan(data) async {
// seeperate by "-", the first index is year, the second index is month
String year = data.substring(0, data.indexOf('-'));
String month = data.substring(data.indexOf('-') + 1);
try {
setBusy(true);
easyLoading.customLoading("Mengunduh Laporan Bulanan...");
await _httpService.get('laporan_bulanan?tahun=$year&bulan=$month');
// if (response.data) {
String urlPdf = '${url}assets/pdf/laporan_bulanan_$month,$year.pdf';
log.i(urlPdf);
FileDownloader.downloadFile(
url: urlPdf,
// name: "THE FILE NAME AFTER DOWNLOADING", //(optional)
onProgress: (fileName, progress) {
// change progress to 0-1
double progressPercent = progress / 100;
easyLoading.showProgress(
progressPercent,
"Downloading: $progress%",
);
},
onDownloadCompleted: (String path) {
easyLoading.dismissLoading();
snackbarService.showSnackbar(
message: "Laporan Bulanan Berhasil Tersimpan di $path",
duration: const Duration(seconds: 3),
);
},
onDownloadError: (String error) {
// log.i('DOWNLOAD ERROR: $error');
snackbarService.showSnackbar(
message: "Laporan Bulanan Gagal Tersimpan: $error",
duration: const Duration(seconds: 3),
);
});
// }
} catch (e) {
log.e(e);
} finally {
setBusy(false);
easyLoading.dismissLoading();
}
}
getLaporanHarian(String filteredByDateData, String dayOfWeek) async {
String date = filteredByDateData;
String day = dayOfWeek;
try {
setBusy(true);
easyLoading.customLoading("Mengunduh Laporan Harian...");
await _httpService.get('laporan_harian?tanggal=$date&hari=$day');
String urlPdf = '${url}assets/pdf/laporan_harian_$day,$date.pdf';
log.i(urlPdf);
FileDownloader.downloadFile(
url: urlPdf,
// name: "THE FILE NAME AFTER DOWNLOADING", //(optional)
onProgress: (fileName, progress) {
// change progress to 0-1
double progressPercent = progress / 100;
easyLoading.showProgress(
progressPercent,
"Downloading: $progress%",
);
},
onDownloadCompleted: (String path) {
easyLoading.dismissLoading();
snackbarService.showSnackbar(
message: "Laporan Harian Berhasil Tersimpan di $path",
duration: const Duration(seconds: 3),
);
},
onDownloadError: (String error) {
// log.i('DOWNLOAD ERROR: $error');
snackbarService.showSnackbar(
message: "Laporan Harian Gagal Tersimpan: $error",
duration: const Duration(seconds: 3),
);
});
} catch (e) {
log.e(e);
} finally {
setBusy(false);
easyLoading.dismissLoading();
}
}
goToLaporanTahunan(String yearIncomeOutcome) async {
// log.i(yearIncomeOutcome);
try {
setBusy(true);
easyLoading.customLoading("Mengunduh Laporan Tahun...");
await _httpService.get('laporan_tahunan?tahun=$yearIncomeOutcome');
// if (response.data) {
String urlPdf = '${url}assets/pdf/laporan_tahunan_$yearIncomeOutcome.pdf';
log.i(urlPdf);
FileDownloader.downloadFile(
url: urlPdf,
// name: "THE FILE NAME AFTER DOWNLOADING", //(optional)
onProgress: (fileName, progress) {
// change progress to 0-1
double progressPercent = progress / 100;
easyLoading.showProgress(
progressPercent,
"Downloading: $progress%",
);
},
onDownloadCompleted: (String path) {
easyLoading.dismissLoading();
snackbarService.showSnackbar(
message: "Laporan Tahunan Berhasil Tersimpan di $path",
duration: const Duration(seconds: 3),
);
},
onDownloadError: (String error) {
// log.i('DOWNLOAD ERROR: $error');
snackbarService.showSnackbar(
message: "Laporan Tahunan Gagal Tersimpan: $error",
duration: const Duration(seconds: 3),
);
});
// }
} catch (e) {
log.e(e);
} finally {
setBusy(false);
easyLoading.dismissLoading();
}
}
}

View File

@ -0,0 +1,80 @@
import 'package:flutter/material.dart';
import 'package:stacked/stacked.dart';
import 'package:stacked_services/stacked_services.dart';
import 'package:validatorless/validatorless.dart';
import '../../../../widgets/my_button.dart';
import '../../../../widgets/my_textformfield.dart';
import './add_donatur_dialog_view_model.dart';
class AddDonaturDialogView extends StatelessWidget {
final DialogRequest? request;
final Function(DialogResponse)? completer;
const AddDonaturDialogView({
Key? key,
this.request,
this.completer,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return ViewModelBuilder<AddDonaturDialogViewModel>.reactive(
viewModelBuilder: () => AddDonaturDialogViewModel(),
onViewModelReady: (AddDonaturDialogViewModel model) async {
await model.init();
},
builder: (
BuildContext context,
AddDonaturDialogViewModel model,
Widget? child,
) {
return Dialog(
child: Container(
padding: const EdgeInsets.all(20),
child: Form(
key: model.formKey,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
const Text(
'Tambah Donatur',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 20),
MyTextFormField(
controller: model.namaController,
hintText: 'Masukkan Nama Donatur',
labelText: 'Nama Donatur',
validator: Validatorless.required(
'Nama Donatur tidak boleh kosong'),
),
const SizedBox(height: 20),
SizedBox(
width: 200,
child: MyButton(
text: 'Tambah',
onPressed: () async {
if (model.formKey.currentState!.validate()) {
// hide keyboard
FocusScope.of(context).unfocus();
bool res = await model.addDonatur();
if (res) {
completer!(DialogResponse(confirmed: true));
}
}
},
),
),
],
),
),
),
);
},
);
}
}

View File

@ -0,0 +1,39 @@
import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import '../../../../../app/app.locator.dart';
import '../../../../../app/app.logger.dart';
import '../../../../../app/core/custom_base_view_model.dart';
import '../../../../../services/http_services.dart';
import '../../../../../services/my_easyloading.dart';
class AddDonaturDialogViewModel extends CustomBaseViewModel {
final log = getLogger('AddDonaturDialogViewModel');
final _httpService = locator<MyHttpServices>();
final easyLoading = locator<MyEasyLoading>();
final formKey = GlobalKey<FormState>();
TextEditingController namaController = TextEditingController();
Future<void> init() async {}
Future<bool> addDonatur() async {
setBusy(true);
easyLoading.showLoading();
try {
await _httpService.postWithFormData(
'donatur',
FormData.fromMap({
'nama_donatur': namaController.text,
}));
return true;
} catch (e) {
log.e(e);
return false;
} finally {
setBusy(false);
easyLoading.dismissLoading();
}
}
}

View File

@ -0,0 +1,737 @@
import 'package:flutter/material.dart';
import 'package:stacked/stacked.dart';
import '../../../../app/themes/app_colors.dart';
import '../../../../app/themes/app_text.dart';
import '../../../../services/other_function.dart';
import '../dana_sosial_admin/dana_sosial_admin_view.dart';
import './dana_sosial_khusus_view_model.dart';
class DanaSosialKhususView extends StatelessWidget {
const DanaSosialKhususView({super.key});
@override
Widget build(BuildContext context) {
return ViewModelBuilder<DanaSosialKhususViewModel>.reactive(
viewModelBuilder: () => DanaSosialKhususViewModel(),
onViewModelReady: (DanaSosialKhususViewModel model) async {
await model.init();
},
builder: (
BuildContext context,
DanaSosialKhususViewModel model,
Widget? child,
) {
return Scaffold(
body: Column(
children: [
// Row(
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
// children: [
// Expanded(
// child: Container(
// padding: const EdgeInsets.symmetric(
// horizontal: 15, vertical: 10),
// width: double.infinity,
// decoration: BoxDecoration(
// color: mainColor,
// borderRadius: BorderRadius.circular(10),
// boxShadow: [
// BoxShadow(
// color: mainGrey.withOpacity(0.5),
// spreadRadius: 5,
// blurRadius: 7,
// offset: const Offset(
// 0, 3), // changes position of shadow
// ),
// ],
// ),
// child: Column(
// crossAxisAlignment: CrossAxisAlignment.start,
// children: [
// Text(
// 'Dana Sosial Bulan Ini',
// style: boldTextStyle.copyWith(
// color: Colors.white,
// fontSize: 20,
// ),
// ),
// const SizedBox(height: 10),
// Row(
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
// children: [
// Text(
// 'Total Dana Sosial',
// style: regularTextStyle.copyWith(
// color: Colors.white,
// fontSize: 15,
// ),
// ),
// Text(
// 'Rp. ${OtherFunction().commaFormat(model.jumlahDonasi)}',
// style: regularTextStyle.copyWith(
// color: Colors.white,
// fontSize: 15,
// ),
// ),
// ],
// ),
// const SizedBox(height: 10),
// Row(
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
// children: [
// Text(
// 'Pengeluaran Dana Sosial',
// style: regularTextStyle.copyWith(
// color: Colors.white,
// fontSize: 15,
// ),
// ),
// Text(
// 'Rp. ${OtherFunction().commaFormat(model.jumlahPengeluaran)}',
// style: regularTextStyle.copyWith(
// color: Colors.white,
// fontSize: 15,
// ),
// ),
// ],
// ),
// ],
// ),
// ),
// ),
// const SizedBox(width: 10),
// Container(
// width: 50,
// height: 50,
// decoration: const BoxDecoration(
// shape: BoxShape.circle,
// color: mainColor,
// ),
// child: IconButton(
// icon: const Icon(
// Icons.filter_list,
// color: Colors.white,
// ),
// onPressed: () {
// model.filterDialog(context);
// },
// ),
// ),
// ],
// ),
const SizedBox(height: 10),
Expanded(
flex: 4,
child: Container(
padding: const EdgeInsets.all(10),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(10),
boxShadow: [
BoxShadow(
color: mainGrey.withOpacity(0.5),
spreadRadius: 5,
blurRadius: 7,
offset:
const Offset(0, 3), // changes position of shadow
),
],
),
child: (model.danaSosialModelList.isEmpty)
? Center(
child: Text(
'Tidak ada data',
style: boldTextStyle.copyWith(
fontSize: 20,
),
),
)
: const TheDataNewly(),
),
),
const SizedBox(
height: 20,
),
Expanded(
flex: 2,
child: Container(
padding: const EdgeInsets.all(15),
width: double.infinity,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(10),
boxShadow: [
BoxShadow(
color: mainGrey.withOpacity(0.5),
spreadRadius: 5,
blurRadius: 7,
offset:
const Offset(0, 3), // changes position of shadow
),
],
),
child: model.monthIncomeOutcome.isEmpty
? const Center(
child: Text(
'Tidak ada data',
))
: const HasilIncomeOutcome(),
),
),
const SizedBox(
height: 20,
),
Container(
padding: const EdgeInsets.all(20),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(10),
boxShadow: [
BoxShadow(
color: mainGrey.withOpacity(0.5),
spreadRadius: 5,
blurRadius: 7,
offset: const Offset(0, 3), // changes position of shadow
),
],
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
const Text(
'Total Pemasukan :',
),
const Expanded(child: SizedBox()),
Text(
'Rp. ${OtherFunction().commaFormat(model.totalIncome)}',
)
],
),
),
],
),
floatingActionButton: model.role == 'admin'
? Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
if (model.role == 'admin')
FloatingActionButton(
heroTag: 'btn1',
onPressed: () {
model.goToTambahDanaSosial();
},
child: const Icon(Icons.add),
),
if (model.role == 'admin') const SizedBox(width: 10),
if (model.role == 'admin')
FloatingActionButton(
heroTag: 'btn2',
onPressed: () async {
bool res = await model.addDonatur();
model.log.i(res);
},
child: const Icon(Icons.person_add_alt),
),
const SizedBox(width: 10),
FloatingActionButton(
heroTag: 'btn3',
onPressed: () {
model.filterDialog(context);
},
child: const Icon(Icons.filter_list),
),
],
)
: null,
floatingActionButtonLocation: FloatingActionButtonLocation.miniEndTop,
);
},
);
}
}
class TheData extends ViewModelWidget<DanaSosialKhususViewModel> {
const TheData({
super.key,
});
@override
Widget build(BuildContext context, DanaSosialKhususViewModel viewModel) {
return ListView.builder(
padding: const EdgeInsets.symmetric(horizontal: 15, vertical: 10),
itemCount: viewModel.danaSosialModelList.length,
itemBuilder: (context, index) {
String jumlahDonasi = viewModel
.danaSosialModelList[index].jenisDonasi !=
'Barang'
? OtherFunction().commaFormat(
int.parse(viewModel.danaSosialModelList[index].jumlah ?? '0'))
: '0';
return Card(
child: ListTile(
title: Text(viewModel.danaSosialModelList[index].tanggal ?? '',
style: boldTextStyle.copyWith(fontSize: 13, color: mainColor)),
subtitle: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
viewModel.danaSosialModelList[index].bentuk == 'Pemasukan'
? 'Pemasukan'
: 'Pengeluaran',
style: boldTextStyle.copyWith(
fontSize: 14,
color: viewModel.danaSosialModelList[index].bentuk ==
'Pemasukan'
? Colors.green
: Colors.red,
),
),
Text(
viewModel.danaSosialModelList[index].nama ?? '-',
style: regularTextStyle.copyWith(
fontSize: 13,
color: viewModel.danaSosialModelList[index].bentuk ==
'Pemasukan'
? Colors.green
: Colors.red,
),
),
Text(
// viewModel.danaSosialModelList[index].jenisDonasi == 'Uang'
// ? (viewModel.isLogin == true ? 'Rp. $jumlahDonasi' : '-')
// : 'Donasi Barang',
viewModel.danaSosialModelList[index].bentuk == 'Pemasukan'
? (viewModel.danaSosialModelList[index].jenisDonasi ==
'Uang'
? (viewModel.isLogin == true
? 'Rp. $jumlahDonasi'
: '-')
: 'Donasi Barang')
: (viewModel.danaSosialModelList[index].jenisDonasi ==
'Uang'
? (viewModel.isLogin == true
? 'Rp. $jumlahDonasi'
: '-')
: 'Pengeluaran Barang'),
style: regularTextStyle.copyWith(
fontSize: 13,
color: viewModel.danaSosialModelList[index].bentuk ==
'Pemasukan'
? Colors.green
: Colors.red,
),
),
Text(
viewModel.danaSosialModelList[index].status ?? '',
style: regularTextStyle.copyWith(
fontSize: 13,
color: viewModel.danaSosialModelList[index].status ==
'Belum Dikonfirmasi'
? Colors.red
: Colors.green,
),
),
],
),
trailing: viewModel.isLogin == null
? null
: (viewModel.isLogin == true
? Row(
mainAxisSize: MainAxisSize.min,
children: [
Container(
width: 50,
height: 50,
decoration: BoxDecoration(
color: mainColor,
borderRadius: BorderRadius.circular(50),
),
child: IconButton(
onPressed: () {
viewModel.goToEditDanaSosial(int.parse(viewModel
.danaSosialModelList[index].idDanaSosial!));
},
icon: const Icon(
Icons.edit,
color: Colors.white,
),
),
),
const SizedBox(width: 10),
Container(
width: 50,
height: 50,
decoration: BoxDecoration(
color: Colors.red,
borderRadius: BorderRadius.circular(50),
),
child: IconButton(
onPressed: () {
viewModel.deleteData(int.parse(viewModel
.danaSosialModelList[index].idDanaSosial!));
},
icon: const Icon(
Icons.delete,
color: Colors.white,
),
),
),
],
)
: null),
),
);
},
);
}
}
class TheDataNewly extends ViewModelWidget<DanaSosialKhususViewModel> {
const TheDataNewly({
super.key,
});
@override
Widget build(BuildContext context, DanaSosialKhususViewModel viewModel) {
return ListView.builder(
itemCount: viewModel.filteredByDateData.length,
itemBuilder: (context, index) {
return Padding(
padding: const EdgeInsets.only(bottom: 30),
child: Container(
padding: const EdgeInsets.all(5),
decoration: BoxDecoration(
borderRadius: const BorderRadius.all(Radius.circular(10)),
boxShadow: [
BoxShadow(
color: mainGrey.withOpacity(0.2),
spreadRadius: 5,
blurRadius: 7,
offset: const Offset(0, 3), // changes position of shadow
),
],
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'${viewModel.otherFunction.changeMonthYear(viewModel.filteredByDateData[index]['month'])} ',
style: boldTextStyle.copyWith(
decoration: TextDecoration.underline,
fontSize: 17,
),
),
const SizedBox(height: 10),
for (int i = 0;
i < viewModel.filteredByDateData[index]['data'].length;
i++)
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'${viewModel.filteredByDateData[index]['data'][i]['date']} : ${viewModel.otherFunction.getDayOfWeek(viewModel.filteredByDateData[index]['data'][i]['date'])}',
style: italicTextStyle.copyWith(
fontWeight: FontWeight.bold, fontSize: 15),
),
const SizedBox(
height: 10,
),
Table(
border: TableBorder.all(
color: Colors.grey,
),
columnWidths: viewModel.role == 'admin'
? const {
0: FlexColumnWidth(
1), // 1/3 of the available width
1: FlexColumnWidth(
1.5), // 2/3 of the available width
2: FlexColumnWidth(
2.5), // 2/3 of the available width
3: FlexColumnWidth(
3), // 2/3 of the available width
4: FlexColumnWidth(
2), // 2/3 of the available width
}
: const {
0: FlexColumnWidth(
1), // 1/3 of the available width
1: FlexColumnWidth(
2), // 2/3 of the available width
2: FlexColumnWidth(
2), // 2/3 of the available width
3: FlexColumnWidth(
3), // 2/3 of the available width
},
children: [
TableRow(
children: [
const TableCell(
child: Center(
child: Text(
'No',
style: boldTextStyle,
),
),
),
const TableCell(
child: Center(
child: Text(
'Jenis',
style: boldTextStyle,
))),
const TableCell(
child: Center(
child: Text(
'Donatur',
style: boldTextStyle,
))),
const TableCell(
child: Center(
child: Text(
'Jumlah /\nKeterangan',
style: boldTextStyle,
),
),
),
if (viewModel.role == 'admin')
const TableCell(
child: Center(
child: Text(
'Aksi',
style: boldTextStyle,
),
),
)
],
),
for (int j = 0;
j <
viewModel
.filteredByDateData[index]['data'][i]
['data_dana']
.length;
j++)
TableRow(
children: [
TableCell(
child: Padding(
padding: const EdgeInsets.symmetric(
vertical: 4,
horizontal: 4,
),
child: Center(
child: Text(
'${j + 1}',
style: regularTextStyle,
),
),
),
),
TableCell(
child: Padding(
padding: const EdgeInsets.symmetric(
vertical: 4,
horizontal: 4,
),
child: Center(
// circle icon
child: viewModel
.filteredByDateData[index]
['data'][i]['data_dana']
[j]
.bentuk ==
'Pemasukan'
? const JenisIconContainer(
color: Colors.green,
icon: Icons.arrow_upward,
)
: const JenisIconContainer(
color: Colors.red,
icon: Icons.arrow_downward,
)),
),
),
TableCell(
child: Padding(
padding: const EdgeInsets.symmetric(
vertical: 4,
horizontal: 4,
),
child: Center(
child: Text(
'${viewModel.filteredByDateData[index]['data'][i]['data_dana'][j].nama == '' ? '-' : viewModel.filteredByDateData[index]['data'][i]['data_dana'][j].nama}',
style: regularTextStyle,
)),
)),
TableCell(
child: Padding(
padding: const EdgeInsets.symmetric(
vertical: 4,
horizontal: 4,
),
child: Center(
child: Text(
viewModel
.filteredByDateData[index]
['data'][i]['data_dana']
[j]
.jenisDonasi ==
'Uang'
? 'Rp. ${viewModel.otherFunction.commaFormat(int.parse(viewModel.filteredByDateData[index]['data'][i]['data_dana'][j].jumlah))}'
: viewModel
.filteredByDateData[index]
['data'][i]['data_dana'][j]
.keterangan,
style: regularTextStyle,
),
),
),
),
if (viewModel.role == 'admin')
TableCell(
child: Center(
child: Padding(
padding: const EdgeInsets.symmetric(
vertical: 4,
horizontal: 4,
),
child: Wrap(
runSpacing: 10,
spacing: 5,
children: [
GestureDetector(
onTap: () {
viewModel.goToEditDanaSosial(
int.parse(viewModel
.filteredByDateData[
index]['data'][i]
['data_dana'][j]
.idDanaSosial));
},
child: JenisIconContainer(
color: Colors.blue[600]!,
icon: Icons.edit,
),
),
GestureDetector(
onTap: () {
viewModel.deleteData(
int.parse(viewModel
.filteredByDateData[index]
['data'][i]
['data_dana'][j]
.idDanaSosial!),
);
},
child: const JenisIconContainer(
color: Colors.red,
icon: Icons.delete,
),
),
],
),
),
),
)
],
),
],
),
const SizedBox(height: 10),
// create a horizontal line
const Divider(
color: Colors.grey,
thickness: 1.0,
),
const SizedBox(height: 10),
],
),
],
),
),
);
},
);
}
}
class HasilIncomeOutcome extends ViewModelWidget<DanaSosialKhususViewModel> {
const HasilIncomeOutcome({
super.key,
});
@override
Widget build(BuildContext context, DanaSosialKhususViewModel viewModel) {
return SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
for (int i = 0; i < viewModel.monthIncomeOutcome.length; i++)
Column(
children: [
Text(
viewModel.otherFunction.changeMonthYear(
viewModel.monthIncomeOutcome[i]['month']),
style: boldTextStyle.copyWith(
decoration: TextDecoration.underline,
fontSize: 17,
),
),
const SizedBox(
height: 5,
),
Table(
border: TableBorder.all(
color: Colors.grey,
),
children: [
const TableRow(children: [
TableCell(
child: Center(
child: Text(
'Pemasukan',
style: boldTextStyle,
))),
TableCell(
child: Center(
child: Text(
'Pengeluaran',
style: boldTextStyle,
)))
]),
TableRow(children: [
TableCell(
child: Center(
child: Text(
'Rp. ${OtherFunction().commaFormat(viewModel.monthIncomeOutcome[i]['income'])}',
style: italicTextStyle,
))),
TableCell(
child: Center(
child: Text(
'Rp. ${OtherFunction().commaFormat(viewModel.monthIncomeOutcome[i]['outcome'])}',
style: italicTextStyle,
)))
]),
],
),
const SizedBox(
height: 5,
),
const Divider(
color: Colors.grey,
thickness: 1,
),
const SizedBox(
height: 5,
),
],
)
],
),
);
}
}

View File

@ -0,0 +1,327 @@
import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
import '../../../../app/app.dialogs.dart';
import '../../../../app/app.locator.dart';
import '../../../../app/app.logger.dart';
import '../../../../app/app.router.dart';
import '../../../../app/core/custom_base_view_model.dart';
import '../../../../model/dana_sosial_model.dart';
import '../../../../services/http_services.dart';
import '../../../../services/my_easyloading.dart';
import '../../../../services/other_function.dart';
class DanaSosialKhususViewModel extends CustomBaseViewModel {
final log = getLogger('DanaSosialKhususViewModel');
final _httpService = locator<MyHttpServices>();
final easyLoading = locator<MyEasyLoading>();
int bulan = DateTime.now().month;
List<DanaSosialModel> danaSosialModelList = [];
List<Map<String, dynamic>> filteredByDateData = []; // newly added
List<Map<String, dynamic>> monthIncomeOutcome = []; // newly added
int totalIncome = 0; // newly added
int totalOutcome = 0; // newly added
String? role;
bool? isLogin;
int jumlahDonasi = 0;
int jumlahPengeluaran = 0;
Future<void> init() async {
await getData();
await getJumlahDonasi();
prefs.then((SharedPreferences prefs) {
role = prefs.getString('role');
isLogin = prefs.getBool('isLogin');
});
// log.i(bulan);
}
getJumlahDonasi() async {
setBusy(true);
easyLoading.showLoading();
// get the month
var bulan = DateTime.now().month;
log.i(bulan);
// change bulan to string and add 0 if it is less than 10
String bulanString = bulan.toString().length == 1 ? '0$bulan' : '$bulan';
log.i(bulanString);
try {
var response =
await _httpService.get('pemasukan_khusus?bulan=$bulanString');
log.i(response.data['jumlah']);
// var theJumlahDonasi = response.data['jumlah'];
jumlahDonasi = response.data['jumlah'];
jumlahPengeluaran = response.data['jumlah_pengeluaran'];
} catch (e) {
log.e(e);
} finally {
setBusy(false);
easyLoading.dismissLoading();
}
}
getData() async {
setBusy(true);
easyLoading.showLoading();
try {
var response = await _httpService.get('dana_sosial_khusus');
// log.i(response.data);
danaSosialModelList = [];
var datanya = response.data['data'];
// log.i(datanya.length);
if (datanya.length > 0) {
for (var item in datanya) {
danaSosialModelList.add(DanaSosialModel.fromJson(item));
}
}
setBusy(false);
notifyListeners();
// log.i(danaSosialModelList.length);
changeByDate(danaSosialModelList);
} catch (e) {
log.e(e);
setBusy(false);
} finally {
easyLoading.dismissLoading();
}
}
//newly added
changeByDate(List<DanaSosialModel> data) {
filteredByDateData = [];
for (var item in data) {
var monthKey =
item.tanggal!.substring(0, 7); // Extracting the year and month
var dateKey = item.tanggal; // The full date
var monthData = filteredByDateData.firstWhere(
(element) => element['month'] == monthKey,
orElse: () => {
'month': monthKey,
'data': [],
});
var dateData =
monthData['data'].firstWhere((element) => element['date'] == dateKey,
orElse: () => {
'date': dateKey,
'data_dana': [],
});
dateData['data_dana'].add(item);
if (!monthData['data'].contains(dateData)) {
monthData['data'].add(dateData);
}
if (!filteredByDateData.contains(monthData)) {
filteredByDateData.add(monthData);
}
}
filteredByDateData.sort((a, b) => a['month'].compareTo(b['month']));
// log.i(filteredByDateData);
// group the data by month
monthIncomeOutcome = [];
for (var item in filteredByDateData) {
var income = 0;
var outcome = 0;
for (var dateData in item['data']) {
for (var danaSosialModel in dateData['data_dana']) {
if (danaSosialModel.bentuk == 'Pemasukan' &&
danaSosialModel.jenisDonasi == 'Uang') {
income += int.parse(danaSosialModel.jumlah ?? '0');
} else if (danaSosialModel.bentuk == 'Pengeluaran' &&
danaSosialModel.jenisDonasi == 'Uang') {
outcome += int.parse(danaSosialModel.jumlah ?? '0');
}
}
}
monthIncomeOutcome.add({
'month': item['month'],
'income': income,
'outcome': outcome,
});
}
// log.i(monthIncomeOutcome);
totalIncome = 0;
totalOutcome = 0;
for (var item in monthIncomeOutcome) {
totalIncome += int.parse(item['income'].toString());
totalOutcome += int.parse(item['outcome'].toString());
}
log.i(totalIncome);
log.i(totalOutcome);
}
goToTambahDanaSosial() {
navigationService.navigateTo(
Routes.tambahDanaSosialView,
arguments: const TambahDanaSosialViewArguments(isKhusus: true),
);
}
getFilter(String sql) async {
setBusy(true);
easyLoading.showLoading();
FormData formData = FormData.fromMap({
'sql': sql,
});
try {
var response = await _httpService.postWithFormData(
'filter_dana_khusus',
formData,
);
// log.i(response.data);
danaSosialModelList = [];
var datanya = response.data['data'];
jumlahDonasi = response.data['jumlah_donasi'];
jumlahPengeluaran = response.data['jumlah_pengeluaran'];
// log.i(datanya.length);
if (datanya.length > 0) {
for (var item in datanya) {
danaSosialModelList.add(DanaSosialModel.fromJson(item));
}
}
setBusy(false);
notifyListeners();
log.i(danaSosialModelList);
} catch (e) {
log.e(e);
setBusy(false);
} finally {
easyLoading.dismissLoading();
}
}
filterDialog(BuildContext context) async {
// create a dialog
final res = await dialogService.showCustomDialog(
variant: DialogType.filterDialogView,
);
if (res!.confirmed) {
String jenisDonasi = res.data['jenisDonasi'] == 'Semua'
? ''
: "jenis = '${res.data['jenisDonasi']}' and ";
String bulan = res.data['bulan'] == 'Semua'
? ''
: "tanggal like '%-${OtherFunction().changeMonth(res.data['bulan'])}-%' and ";
String tahun = res.data['tahun'] == 'Semua'
? ''
: 'tanggal like "%${res.data['tahun']}-%" and ';
String status = res.data['status'] == 'Semua'
? ''
: (res.data['status'] == 'Belum Dikonfirmasi')
? 'status = 0'
: 'status = 1';
if (jenisDonasi == 'Semua' &&
bulan == 'Semua' &&
tahun == 'Semua' &&
status == 'Semua') {
getData();
return;
}
String sql =
'Select * from tb_dana_sosial_khusus where $jenisDonasi$bulan$tahun$status';
// check the last 3 character if it is 'or ' then remove it
// if (sql.substring(sql.length - 3) == 'or ') {
// sql = sql.substring(0, sql.length - 3);
// }
if (sql.substring(sql.length - 4) == 'and ') {
sql = sql.substring(0, sql.length - 4);
}
log.i(sql);
getFilter(sql);
}
}
goToEditDanaSosial(int id) async {
navigationService.navigateTo(
Routes.detailDanaSosialView,
arguments: DetailDanaSosialViewArguments(
id: id,
isKhusus: true,
),
);
}
deleteData(int parse) async {
await dialogService
.showDialog(
title: 'Hapus Data',
description: 'Apakah anda yakin ingin menghapus data ini?',
buttonTitle: 'Hapus',
cancelTitle: 'Batal',
buttonTitleColor: Colors.red,
cancelTitleColor: Colors.green,
)
.then(
(value) async {
if (value!.confirmed) {
easyLoading.showLoading();
setBusy(true);
try {
var response = await _httpService.postWithFormData(
'hapus_dana_sosial_khusus',
FormData.fromMap({
'id_dana_sosial': parse,
}));
log.i(response.data);
easyLoading.dismissLoading();
easyLoading.showSuccess('Data berhasil dihapus');
getData();
getJumlahDonasi();
} on DioError catch (e) {
// easyLoading.dismissLoading();
log.e(e);
easyLoading.showError('Terjadi kesalahan');
} finally {
setBusy(false);
easyLoading.dismissLoading();
}
} else {
log.i('cancel');
return;
}
},
);
}
Future<bool> addDonatur() async {
var res = await dialogService.showCustomDialog(
variant: DialogType.addDonaturDialogView,
);
if (res!.confirmed) {
snackbarService.showSnackbar(
message: 'Berhasil menambahkan donatur',
duration: const Duration(seconds: 2),
);
return true;
}
return false;
}
}

View File

@ -44,7 +44,7 @@ class DataSiswaView extends StatelessWidget {
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'Total Siswa',
'Total Anak Panti',
style: regularTextStyle.copyWith(
color: Colors.white,
fontSize: 15,
@ -93,8 +93,23 @@ class DataSiswaView extends StatelessWidget {
itemBuilder: (context, index) {
return Card(
child: ListTile(
leading: Container(
alignment: Alignment.center,
width: 25,
height: 25,
decoration: BoxDecoration(
color: mainColor,
borderRadius: BorderRadius.circular(50),
),
child: Text(
'${index + 1}',
style: regularTextStyle.copyWith(
color: Colors.white),
),
),
title: Text(
model.siswaModelList[index].nama ?? '',
model.otherFunction.capitalizeEachWord(
model.siswaModelList[index].nama!),
style: boldTextStyle.copyWith(
fontSize: 13, color: mainColor)),
subtitle: Text(

View File

@ -49,7 +49,7 @@ class EditDialogSiswaView extends StatelessWidget {
children: [
const Center(
child: Text(
'Edit Data Siswa',
'Edit Data Anak Panti',
style: boldTextStyle,
),
),

View File

@ -29,7 +29,7 @@ class EditSiswaView extends StatelessWidget {
return Scaffold(
appBar: AppBar(
title: const Text(
"Informasi Data Siswa",
"Informasi Data Anak Panti",
style: TextStyle(
color: Colors.white,
fontSize: 20,

View File

@ -16,6 +16,7 @@ class FilterDialogViewModel extends CustomBaseViewModel {
'April',
'Mei',
'Juni',
'Juli',
'Agustus',
'September',
'Oktober',
@ -26,6 +27,7 @@ class FilterDialogViewModel extends CustomBaseViewModel {
String tahun = 'Semua';
List<String> tahunList = [
'Semua',
'2024',
'2023',
'2022',
];

View File

@ -47,7 +47,7 @@ class ProfilView extends StatelessWidget {
SizedBox(width: 15),
Expanded(
child: Text(
"081 343 434 343",
"085 298 962 023",
textAlign: TextAlign.justify,
style: regularTextStyle,
),

View File

@ -56,6 +56,13 @@ class StrukturOrganisasiView extends StatelessWidget {
const SizedBox(
height: 20,
),
FirstWidget(
title: 'Wakil Bendahara',
data: model.dataWakilBendahara,
),
const SizedBox(
height: 20,
),
SecondWidget(
title: 'Seksi Pengasuh',
data: model.dataPengasuh,

View File

@ -16,6 +16,7 @@ class StrukturOrganisasiViewModel extends CustomBaseViewModel {
Map<String, dynamic> dataKetua = {};
Map<String, dynamic> dataSekretaris = {};
Map<String, dynamic> dataBendahara = {};
Map<String, dynamic> dataWakilBendahara = {};
Map<String, dynamic> dataPengasuh = {};
int dataPengasuhLength = 0;
@ -63,6 +64,7 @@ class StrukturOrganisasiViewModel extends CustomBaseViewModel {
getData('Ketua', false, null);
getData('Sekretaris', false, null);
getData('Bendahara', false, null);
getData('Wakil Bendahara', false, null);
getData('Seksi Pengasuh', true, dataPengasuhLength);
getData('Seksi Ibadah', true, dataIbadahLength);
getData('Seksi Pendidikan', true, dataPendidikanLength);
@ -108,6 +110,8 @@ class StrukturOrganisasiViewModel extends CustomBaseViewModel {
dataSekretaris = data;
} else if (jabatan == 'Bendahara') {
dataBendahara = data;
} else if (jabatan == 'Wakil Bendahara') {
dataWakilBendahara = data;
} else if (jabatan == 'Seksi Pengasuh') {
dataPengasuh = data;
dataPengasuhLength = length!;

View File

@ -9,14 +9,18 @@ import './detail_dana_sosial_view_model.dart';
class DetailDanaSosialView extends StatelessWidget {
final int id;
const DetailDanaSosialView({Key? key, required this.id}) : super(key: key);
final bool isKhusus;
const DetailDanaSosialView(
{Key? key, required this.id, this.isKhusus = false})
: super(key: key);
@override
Widget build(BuildContext context) {
return ViewModelBuilder<DetailDanaSosialViewModel>.reactive(
viewModelBuilder: () => DetailDanaSosialViewModel(),
onViewModelReady: (DetailDanaSosialViewModel model) async {
await model.init(id);
await model.init(id, isKhusus);
},
builder: (
BuildContext context,
@ -37,7 +41,7 @@ class DetailDanaSosialView extends StatelessWidget {
child: CircularProgressIndicator(),
)
: (model.danaSosialModel!.bentuk == 'Pemasukan'
? const PemasukanWidget()
? const SafeArea(child: PemasukanWidget())
: const PengeluaranWidget()),
),
);
@ -205,147 +209,183 @@ class PemasukanWidget extends ViewModelWidget<DetailDanaSosialViewModel> {
@override
Widget build(BuildContext context, DetailDanaSosialViewModel viewModel) {
return Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Align(
alignment: Alignment.centerLeft,
child: Text(
"Nama Donator",
style: regularTextStyle.copyWith(color: mainColor),
),
),
MyTextFormField(
controller: viewModel.namaController,
maxLines: 1,
readOnly: true,
),
const SizedBox(
height: 15,
),
Align(
alignment: Alignment.centerLeft,
child: Text(
"Tanggal",
style: regularTextStyle.copyWith(color: mainColor),
),
),
MyTextFormField(
controller: viewModel.tanggalController,
maxLines: 1,
readOnly: true,
),
const SizedBox(
height: 15,
),
Align(
alignment: Alignment.centerLeft,
child: Text(
"Jenis",
style: regularTextStyle.copyWith(color: mainColor),
),
),
MyTextFormField(
controller: viewModel.jenisController,
maxLines: 1,
readOnly: true,
),
Visibility(
visible: viewModel.jenisBool,
child: const SizedBox(
height: 15,
),
),
Visibility(
visible: viewModel.jenisBool,
child: Align(
alignment: Alignment.centerLeft,
child: Text(
"Jumlah",
style: regularTextStyle.copyWith(color: mainColor),
return SingleChildScrollView(
child: SizedBox(
height: MediaQuery.of(context).size.height,
child: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Align(
alignment: Alignment.centerLeft,
child: Text(
"Nama Donator",
style: regularTextStyle.copyWith(color: mainColor),
),
),
),
),
Visibility(
visible: viewModel.jenisBool,
child: MyTextFormField(
controller: viewModel.jumlahController,
maxLines: 1,
readOnly: true,
),
),
Visibility(
visible: !viewModel.jenisBool,
child: const SizedBox(
height: 15,
),
),
Visibility(
visible: !viewModel.jenisBool,
child: Align(
alignment: Alignment.centerLeft,
child: Text(
"Keterangan",
style: regularTextStyle.copyWith(color: mainColor),
MyTextFormField(
controller: viewModel.namaController,
maxLines: 1,
readOnly: true,
),
),
),
Visibility(
visible: !viewModel.jenisBool,
child: MyTextFormField(
controller: viewModel.keteranganController,
maxLines: 2,
readOnly: true,
),
),
const SizedBox(
height: 15,
),
Expanded(
child: Align(
alignment: Alignment.centerRight,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text(
"Tanda Tangan",
const SizedBox(
height: 15,
),
Align(
alignment: Alignment.centerLeft,
child: Text(
"Tanggal",
style: regularTextStyle.copyWith(color: mainColor),
),
),
MyTextFormField(
controller: viewModel.tanggalController,
maxLines: 1,
readOnly: true,
),
const SizedBox(
height: 15,
),
Align(
alignment: Alignment.centerLeft,
child: Text(
"Jenis",
style: regularTextStyle.copyWith(color: mainColor),
),
),
MyTextFormField(
controller: viewModel.jenisController,
maxLines: 1,
readOnly: true,
),
Visibility(
visible: viewModel.jenisBool,
child: const SizedBox(
height: 15,
),
),
Visibility(
visible: viewModel.jenisBool,
child: Align(
alignment: Alignment.centerLeft,
child: Text(
"Jumlah",
style: regularTextStyle.copyWith(color: mainColor),
),
SizedBox(
height: 150,
width: 150,
child: viewModel.danaSosialModel == null
? Container(
decoration: BoxDecoration(
border: Border.all(color: mainColor),
),
)
: (viewModel.danaSosialModel!.status! ==
'Belum Dikonfirmasi'
? const TtdWidget()
: Image.asset(
'assets/qrcode.png',
fit: BoxFit.cover,
)),
),
const SizedBox(
height: 10,
),
Text(
"Dr. Andi Fitriani D, S.Ag, M.Pd",
style: regularTextStyle.copyWith(
color: mainColor,
fontWeight: FontWeight.bold,
),
),
// create a horizontal line
],
),
),
),
Visibility(
visible: viewModel.jenisBool,
child: MyTextFormField(
controller: viewModel.jumlahController,
maxLines: 1,
readOnly: true,
),
),
Visibility(
visible: !viewModel.jenisBool,
child: const SizedBox(
height: 15,
),
),
if (!viewModel.jenisBool)
Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Jenis Barang",
style: regularTextStyle.copyWith(color: mainColor),
),
MyTextFormField(
controller: viewModel.jenisBarangController,
maxLines: 1,
readOnly: true,
),
const SizedBox(
height: 15,
),
Text(
"Jumlah Barang",
style: regularTextStyle.copyWith(color: mainColor),
),
MyTextFormField(
controller: viewModel.jumlahBarangController,
maxLines: 1,
readOnly: true,
),
const SizedBox(
height: 15,
),
],
),
Visibility(
visible: !viewModel.jenisBool,
child: Align(
alignment: Alignment.centerLeft,
child: Text(
"Keterangan",
style: regularTextStyle.copyWith(color: mainColor),
),
),
),
Visibility(
visible: !viewModel.jenisBool,
child: MyTextFormField(
controller: viewModel.keteranganController,
maxLines: 2,
readOnly: true,
),
),
const SizedBox(
height: 15,
),
Expanded(
child: Align(
alignment: Alignment.centerRight,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text(
"Tanda Tangan",
style: regularTextStyle.copyWith(color: mainColor),
),
SizedBox(
height: 150,
width: 150,
child: viewModel.danaSosialModel == null
? Container(
decoration: BoxDecoration(
border: Border.all(color: mainColor),
),
)
: (viewModel.danaSosialModel!.status! ==
'Belum Dikonfirmasi'
? const TtdWidget()
: Image.asset(
'assets/qrcode.png',
fit: BoxFit.cover,
)),
),
const SizedBox(
height: 10,
),
Text(
"DRA. HJ. CIA",
style: regularTextStyle.copyWith(
color: mainColor,
fontWeight: FontWeight.bold,
),
),
// create a horizontal line
],
),
),
),
],
),
],
),
);
}
}
@ -361,7 +401,7 @@ class TtdWidget extends ViewModelWidget<DetailDanaSosialViewModel> {
decoration: BoxDecoration(
border: Border.all(color: mainColor),
),
child: viewModel.role == 'pimpinan'
child: viewModel.role == 'pimpinan' || viewModel.role == 'admin'
? InkWell(
onTap: () {
viewModel.handleTtd();

View File

@ -15,6 +15,8 @@ class DetailDanaSosialViewModel extends CustomBaseViewModel {
final _httpService = locator<MyHttpServices>();
final easyLoading = locator<MyEasyLoading>();
bool isKhusus = false;
int? idDanaSosial;
DanaSosialModel? danaSosialModel;
bool jenisBool = true;
@ -29,8 +31,14 @@ class DetailDanaSosialViewModel extends CustomBaseViewModel {
TextEditingController bentukController = TextEditingController();
Future<void> init(int id) async {
// my revision syntax
TextEditingController jenisBarangController = TextEditingController();
TextEditingController jumlahBarangController = TextEditingController();
// TextEditingController satuanController = TextEditingController();
Future<void> init(int id, bool isKhusus) async {
log.i('init and id: $id');
this.isKhusus = isKhusus;
getData(id);
idDanaSosial = id;
prefs.then((SharedPreferences prefs) {
@ -42,7 +50,10 @@ class DetailDanaSosialViewModel extends CustomBaseViewModel {
setBusy(true);
easyLoading.showLoading();
try {
var response = await _httpService.get('dana_sosial_detail?id=$id');
String url = isKhusus
? 'dana_sosial_khusus_detail?id=$id'
: 'dana_sosial_detail?id=$id';
var response = await _httpService.get(url);
log.i(response.data['data']);
danaSosialModel = DanaSosialModel.fromJson(response.data['data']);
namaController.text = danaSosialModel!.nama!;
@ -54,6 +65,12 @@ class DetailDanaSosialViewModel extends CustomBaseViewModel {
bentukController.text = danaSosialModel!.bentuk!;
// my revision syntax
jenisBarangController.text = danaSosialModel!.jenisBarang!;
jumlahBarangController.text =
'${danaSosialModel!.jumlahBarang!} ${danaSosialModel!.satuan!}';
// satuanController.text = danaSosialModel!.satuan! ;
if (danaSosialModel!.jenisDonasi == 'Uang') {
jenisBool = true;
} else {
@ -86,8 +103,9 @@ class DetailDanaSosialViewModel extends CustomBaseViewModel {
FormData formData = FormData.fromMap({
'id': idDanaSosial,
});
var response =
await _httpService.postWithFormData('dana_sosial_ttd', formData);
String url = isKhusus ? 'dana_sosial_khusus_ttd' : 'dana_sosial_ttd';
var response = await _httpService.postWithFormData(url, formData);
log.i(response.data);
getData(idDanaSosial!);

View File

@ -18,11 +18,12 @@ class PimpinanIndexTrackingViewModel extends IndexTrackingViewModel {
final _bottomNavBarList = [
{
'name': 'Siswa',
'name': 'List',
'icon': Icons.people_alt_outlined,
'header': 'List Siswa'
'header': 'List Anak Panti'
},
{'name': 'Dana', 'icon': Icons.money, 'header': 'Dana Sosial'},
// {'name': 'Dana', 'icon': Icons.money, 'header': 'Dana Sosial Khusus'},
{
'name': 'Profil',
'icon': Icons.person_4_outlined,
@ -34,6 +35,7 @@ class PimpinanIndexTrackingViewModel extends IndexTrackingViewModel {
final List<String> _views = [
PimpinanIndexTrackingViewRoutes.dataSiswaView,
PimpinanIndexTrackingViewRoutes.danaSosialAdminView,
// PimpinanIndexTrackingViewRoutes.danaSosialKhususView,
PimpinanIndexTrackingViewRoutes.profilView,
];
Future<void> init() async {

View File

@ -9,14 +9,19 @@ import '../../widgets/my_textformfield.dart';
import './tambah_dana_sosial_view_model.dart';
class TambahDanaSosialView extends StatelessWidget {
const TambahDanaSosialView({super.key});
final bool isKhusus;
const TambahDanaSosialView({
Key? key,
this.isKhusus = false,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return ViewModelBuilder<TambahDanaSosialViewModel>.reactive(
viewModelBuilder: () => TambahDanaSosialViewModel(),
onViewModelReady: (TambahDanaSosialViewModel model) async {
await model.init();
await model.init(isKhusus);
},
builder: (
BuildContext context,
@ -66,6 +71,7 @@ class TambahDanaSosialView extends StatelessWidget {
// model.setSelectedbentukDonasi(newValue!);
model.log.i(newValue);
model.bentukDonasi = newValue!;
model.notifyListeners();
},
items: model.bentukDonasiList.map((String value) {
@ -91,7 +97,8 @@ class TambahDanaSosialView extends StatelessWidget {
),
),
Visibility(
visible: model.bentukDonasi == 'Pemasukan',
visible: model.bentukDonasi == 'Pemasukan' &&
isKhusus == false,
child: MyTextFormField(
hintText: "Nama Donatur",
controller: model.namaController,
@ -100,6 +107,51 @@ class TambahDanaSosialView extends StatelessWidget {
// 'Nama Donatur tidak boleh kosong'),
),
),
Visibility(
visible: model.bentukDonasi == 'Pemasukan' &&
isKhusus == true,
child: Container(
width: double.infinity,
height: 60,
padding: const EdgeInsets.symmetric(horizontal: 10),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(25),
border: Border.all(
color: mainColor,
),
),
child: DropdownButtonHideUnderline(
child: DropdownButton<String>(
value: model.donaturSelected,
onChanged: (String? newValue) {
// model.setSelectedjenisDonasi(newValue!);
model.log.i(newValue);
model.donaturSelected = newValue!;
// check where is the index and get the ['id_donatur']
var index = model.listDonatur.indexWhere(
(element) => element == newValue,
);
model.donaturSelectedIndex = int.parse(
model.listDonaturMap[index]['id_donatur'],
);
model.log.i(model.donaturSelectedIndex);
},
items: model.listDonatur.map((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(
value,
style: regularTextStyle.copyWith(
fontSize: 16,
),
),
);
}).toList(),
),
),
),
),
Visibility(
visible: model.bentukDonasi == 'Pemasukan',
child: const SizedBox(height: 20),
@ -141,6 +193,130 @@ class TambahDanaSosialView extends StatelessWidget {
),
),
),
// ini jika barang
if (model.jenisDonasi == 'Barang')
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(height: 20),
Text(
"Jenis Barang",
style:
regularTextStyle.copyWith(color: mainColor),
),
Container(
width: double.infinity,
height: 60,
padding:
const EdgeInsets.symmetric(horizontal: 10),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(25),
border: Border.all(
color: mainColor,
),
),
child: DropdownButtonHideUnderline(
child: DropdownButton<String>(
value: model.jenisBarangSelected,
onChanged: (String? newValue) {
// model.setSelectedjenisDonasi(newValue!);
model.log.i(newValue);
model.jenisBarangSelected = newValue!;
model.changeSatuan(newValue);
model.notifyListeners();
},
items:
model.jenisBarangList.map((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(
value,
style: regularTextStyle.copyWith(
fontSize: 16,
),
),
);
}).toList(),
),
),
),
],
),
// ini jika barang dan jenis barang beras dll
if (model.jenisDonasi == 'Barang' &&
(model.jenisBarangSelected == 'Beras' ||
model.jenisBarangSelected == 'Mi Instan' ||
model.jenisBarangSelected == 'Telur' ||
model.jenisBarangSelected == 'Gula'))
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(height: 20),
Text(
"Pilih Satuan ${model.jenisBarangSelected}",
style:
regularTextStyle.copyWith(color: mainColor),
),
Container(
width: double.infinity,
height: 60,
padding:
const EdgeInsets.symmetric(horizontal: 10),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(25),
border: Border.all(
color: mainColor,
),
),
child: DropdownButtonHideUnderline(
child: DropdownButton<String>(
value: model.satuanSelected,
onChanged: (String? newValue) {
// model.setSelectedjenisDonasi(newValue!);
model.log.i(newValue);
model.satuanSelected = newValue!;
model.notifyListeners();
},
items: model.satuanList.map((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(
value,
style: regularTextStyle.copyWith(
fontSize: 16,
),
),
);
}).toList(),
),
),
),
],
),
// ini jika barang dan jenis barang dll
if (model.jenisDonasi == 'Barang')
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(height: 20),
Text(
"Jumlah ${model.satuanSelected}",
style:
regularTextStyle.copyWith(color: mainColor),
),
MyTextFormField(
hintText: "Jumlah ${model.satuanSelected}",
controller: model.jumlahBarangController,
maxLines: 1,
keyboardType: TextInputType.number,
maxLength: 3,
// validator: Validatorless.required(
// 'Nama Donatur tidak boleh kosong'),
),
],
),
Visibility(
visible: model.jenisDonasi == 'Uang',
child: const SizedBox(height: 20),
@ -212,6 +388,15 @@ class TambahDanaSosialView extends StatelessWidget {
MyButton(
text: "Simpan Data",
onPressed: () {
if (isKhusus &&
model.donaturSelected == '-Tiada Donatur-') {
model.snackbarService.showSnackbar(
message: 'Donatur harus diisi terlebih dahulu',
title: 'Gagal',
duration: const Duration(seconds: 2),
);
return;
}
if (model.formKey.currentState!.validate()) {
model.log.i('Form Valid');
model.addData();

View File

@ -23,10 +23,77 @@ class TambahDanaSosialViewModel extends CustomBaseViewModel {
TextEditingController namaController = TextEditingController();
TextEditingController jumlahController = TextEditingController();
TextEditingController jumlahBarangController = TextEditingController();
TextEditingController tanggalController = TextEditingController();
TextEditingController keteranganController = TextEditingController();
Future<void> init() async {}
// my revision syntax
List<String> jenisBarangList = [
'Beras',
'Minyak',
'Mi Instan',
'Telur',
'Gula',
'Susu',
'Pakaian'
];
String jenisBarangSelected = 'Beras';
String satuanSelected = 'Kg';
// TextEditingController jumlahBarangController = TextEditingController();
bool isJenisBarangSelected = true;
List<String> satuanLiterKg = ['Liter', 'Kg'];
List<String> satuanBungkusDos = ['Bungkus', 'Dos'];
List<String> satuanButirRak = ['Butir', 'Rak'];
List<String> satuanList = ['Liter', 'Kg'];
// end of my revision syntax
// the new revision syntax
bool isKhusus = false;
List<String> listDonatur = ['-Tiada Donatur-'];
List<Map<String, dynamic>> listDonaturMap = [];
String donaturSelected = '-Tiada Donatur-';
int donaturSelectedIndex = 0;
// end of the new revision syntax
Future<void> init(bool isKhusus) async {
this.isKhusus = isKhusus;
if (isKhusus) {
bentukDonasiList = ['Pemasukan'];
getDonatur();
}
}
getDonatur() async {
setBusy(true);
easyLoading.customLoading('Mengambil data...');
try {
var response = await _httpService.get('donatur');
Map<String, dynamic> data = response.data;
// log.i(data);
int jumlah = data['jumlah'];
if (jumlah > 0) {
listDonatur.clear();
for (var i = 0; i < data['data'].length; i++) {
listDonatur.add(data['data'][i]['nama_donatur']);
listDonaturMap.add(data['data'][i]);
}
// get the [id_donatur] of the first [donatur
donaturSelected = listDonatur[0];
donaturSelectedIndex = int.parse(listDonaturMap[0]['id_donatur']);
log.i(donaturSelectedIndex);
}
} catch (e) {
log.e(e);
} finally {
setBusy(false);
easyLoading.dismissLoading();
}
}
void changeDate(BuildContext context) async {
// get today's date
@ -46,6 +113,7 @@ class TambahDanaSosialViewModel extends CustomBaseViewModel {
void addData() async {
easyLoading.customLoading('Menambahkan data...');
log.i(donaturSelectedIndex);
try {
var formData = FormData.fromMap({
'bentuk': bentukDonasi,
@ -54,9 +122,17 @@ class TambahDanaSosialViewModel extends CustomBaseViewModel {
'tanggal': tanggalController.text,
'ket': keteranganController.text,
'jenis': jenisDonasi,
'jenis_barang': jenisDonasi == 'Barang' ? jenisBarangSelected : null,
'satuan': jenisDonasi == 'Barang' ? satuanSelected : null,
'jumlah_barang':
jenisDonasi == 'Barang' ? jumlahBarangController.text : null,
'donatur': isKhusus ? donaturSelectedIndex : null,
});
var response =
await _httpService.postWithFormData('dana_sosial', formData);
// await _httpService.postWithFormData('dana_sosial', formData);
await _httpService.postWithFormData(
!isKhusus ? 'dana_sosial' : 'dana_sosial_khusus', formData);
log.i(response.data);
easyLoading.showSuccess(" Data berhasil ditambahkan");
navigationService.navigateTo(Routes.adminIndexTrackingView);
@ -71,4 +147,49 @@ class TambahDanaSosialViewModel extends CustomBaseViewModel {
easyLoading.dismissLoading();
}
}
// my revision syntax
changeSatuan(String value) {
jenisBarangSelected = value;
switch (value) {
case 'Beras':
isJenisBarangSelected = true;
satuanSelected = 'Kg';
satuanList = satuanLiterKg;
break;
case 'Minyak':
isJenisBarangSelected = false;
satuanSelected = 'Liter';
break;
case 'Mi Instan':
isJenisBarangSelected = true;
satuanSelected = 'Bungkus';
satuanList = satuanBungkusDos;
break;
case 'Telur':
isJenisBarangSelected = true;
satuanSelected = 'Butir';
satuanList = satuanButirRak;
break;
case 'Gula':
isJenisBarangSelected = true;
satuanSelected = 'Kg';
satuanList = satuanLiterKg;
break;
case 'Susu':
isJenisBarangSelected = false;
satuanSelected = 'Liter';
break;
case 'Pakaian':
isJenisBarangSelected = false;
satuanSelected = 'Helai';
// satuanList = satuanButirRak;
break;
default:
satuanSelected = '';
}
// notifyListeners();
}
}

View File

@ -15,11 +15,12 @@ class UserIndexTrackingViewModel extends IndexTrackingViewModel {
final _bottomNavBarList = [
{
'name': 'Siswa',
'name': 'List',
'icon': Icons.people_alt_outlined,
'header': 'List Siswa'
'header': 'List Anak Panti'
},
{'name': 'Dana', 'icon': Icons.money, 'header': 'Dana Sosial'},
// {'name': 'Dana', 'icon': Icons.money, 'header': 'Dana Sosial Khusus'},
{
'name': 'Profil',
'icon': Icons.person_4_outlined,
@ -39,6 +40,7 @@ class UserIndexTrackingViewModel extends IndexTrackingViewModel {
final List<String> _views = [
UserIndexTrackingViewRoutes.dataSiswaView,
UserIndexTrackingViewRoutes.danaSosialAdminView,
// UserIndexTrackingViewRoutes.danaSosialKhususView,
UserIndexTrackingViewRoutes.profilView,
UserIndexTrackingViewRoutes.visiMisiView,
UserIndexTrackingViewRoutes.sejarahView,

View File

@ -20,6 +20,7 @@ class MyTextFormField extends StatelessWidget {
this.keyboardType = TextInputType.text,
this.initialValue,
this.enabled = true,
this.maxLength,
}) : super(key: key);
final String? labelText;
@ -37,10 +38,12 @@ class MyTextFormField extends StatelessWidget {
final TextInputType keyboardType;
final String? initialValue;
final bool enabled;
final int? maxLength;
@override
Widget build(BuildContext context) {
return TextFormField(
maxLength: maxLength,
enabled: enabled,
initialValue: initialValue,
onEditingComplete: onEditingComplete,

View File

@ -254,6 +254,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "3.0.5"
flutter_file_downloader:
dependency: "direct main"
description:
name: flutter_file_downloader
sha256: e36f1a23937c83b96003ecc48f3227acbd468a1ff26be87959cecd057222632a
url: "https://pub.dev"
source: hosted
version: "1.2.1"
flutter_holo_date_picker:
dependency: "direct main"
description:

View File

@ -53,6 +53,7 @@ dependencies:
shared_preferences:
# flutter_hooks:
http_parser:
flutter_file_downloader: ^1.2.1
dev_dependencies:
flutter_test: