Compare commits
10 Commits
b82edc2db9
...
0ad81dd67d
Author | SHA1 | Date |
---|---|---|
kicap | 0ad81dd67d | |
kicap | 41ecbc0065 | |
kicap | 667aae745b | |
kicap | b1dc1851a4 | |
kicap | 4f7a8b870c | |
kicap | 914e24706b | |
kicap | 30131e5ffe | |
kicap | 757198cb83 | |
kicap | e0b5213a3b | |
kicap | 949474b8ef |
10
.env
|
@ -1,2 +1,8 @@
|
|||
url = 'http://20.20.20.25/perumahan/'
|
||||
api_url = 'http://20.20.20.25/perumahan/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/'
|
|
@ -31,6 +31,7 @@ migrate_working_dir/
|
|||
.pub-cache/
|
||||
.pub/
|
||||
/build/
|
||||
.env
|
||||
|
||||
# Symbolication related
|
||||
app.*.symbols
|
||||
|
|
|
@ -1,25 +1,13 @@
|
|||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.example.panti_asuhan">
|
||||
<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">
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.panti_asuhan">
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<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"/>
|
||||
|
@ -27,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>
|
||||
|
|
Before Width: | Height: | Size: 544 B After Width: | Height: | Size: 205 KiB |
Before Width: | Height: | Size: 442 B After Width: | Height: | Size: 205 KiB |
Before Width: | Height: | Size: 721 B After Width: | Height: | Size: 205 KiB |
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 205 KiB |
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 205 KiB |
After Width: | Height: | Size: 433 KiB |
|
@ -1,15 +1,29 @@
|
|||
import 'package:panti_asuhan/ui/views/admin_index_tracking/admin_index/admin_index_view.dart';
|
||||
import 'package:panti_asuhan/ui/views/admin_index_tracking/dana_sosial_admin/dana_sosial_admin_view.dart';
|
||||
import 'package:panti_asuhan/ui/views/admin_index_tracking/data_siswa/data_siswa_view.dart';
|
||||
import 'package:panti_asuhan/ui/views/admin_index_tracking/profil/profil_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';
|
||||
import '../ui/views/admin_index_tracking/sejarah/sejarah_view.dart';
|
||||
import '../ui/views/admin_index_tracking/struktur_organisasi/edit_strukrur_organisasi_dialog/edit_strukrur_organisasi_dialog_view.dart';
|
||||
import '../ui/views/admin_index_tracking/struktur_organisasi/struktur_organisasi_view.dart';
|
||||
import '../ui/views/admin_index_tracking/visi_misi/visi_misi_view.dart';
|
||||
import '../ui/views/detail_dana_sosial/detail_dana_sosial_view.dart';
|
||||
import '../ui/views/login_screen/login_screen_view.dart';
|
||||
import '../ui/views/pimpinan_index_tracking/pimpinan_index_tracking/pimpinan_index_tracking_view.dart';
|
||||
import '../ui/views/splash_screen/splash_screen_view.dart';
|
||||
import '../ui/views/tambah_dana_sosial/tambah_dana_sosial_view.dart';
|
||||
import '../ui/views/user_index_tracking/user_index_tracking_view.dart';
|
||||
|
||||
@StackedApp(
|
||||
routes: [
|
||||
|
@ -18,12 +32,51 @@ import '../ui/views/splash_screen/splash_screen_view.dart';
|
|||
MaterialRoute(
|
||||
page: AdminIndexTrackingView,
|
||||
children: [
|
||||
MaterialRoute(page: AdminIndexView, initial: true),
|
||||
// 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: TambahDanaSosialView),
|
||||
MaterialRoute(page: EditSiswaView),
|
||||
MaterialRoute(page: DetailDanaSosialView),
|
||||
MaterialRoute(
|
||||
page: PimpinanIndexTrackingView,
|
||||
children: [
|
||||
// MaterialRoute(page: AdminIndexView, initial: true),
|
||||
MaterialRoute(page: DanaSosialAdminView),
|
||||
MaterialRoute(page: DanaSosialKhususView),
|
||||
MaterialRoute(page: DataSiswaView),
|
||||
MaterialRoute(page: ProfilView),
|
||||
],
|
||||
),
|
||||
MaterialRoute(
|
||||
page: UserIndexTrackingView,
|
||||
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),
|
||||
],
|
||||
),
|
||||
],
|
||||
dialogs: [
|
||||
StackedDialog(classType: AddSiswaDialogView),
|
||||
StackedDialog(classType: FilterDialogView),
|
||||
StackedDialog(classType: EditStrukrurOrganisasiDialogView),
|
||||
StackedDialog(classType: EditDialogSiswaView),
|
||||
StackedDialog(classType: AddDonaturDialogView),
|
||||
],
|
||||
dependencies: [
|
||||
LazySingleton(classType: NavigationService),
|
||||
|
@ -34,6 +87,7 @@ import '../ui/views/splash_screen/splash_screen_view.dart';
|
|||
|
||||
LazySingleton(classType: MyEasyLoading),
|
||||
LazySingleton(classType: MyHttpServices),
|
||||
LazySingleton(classType: OtherFunction),
|
||||
],
|
||||
logger: StackedLogger(),
|
||||
)
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
// **************************************************************************
|
||||
// StackedDialogGenerator
|
||||
// **************************************************************************
|
||||
|
||||
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';
|
||||
|
||||
enum DialogType {
|
||||
addSiswaDialogView,
|
||||
filterDialogView,
|
||||
editStrukrurOrganisasiDialogView,
|
||||
editDialogSiswaView,
|
||||
addDonaturDialogView,
|
||||
}
|
||||
|
||||
void setupDialogUi() {
|
||||
final dialogService = locator<DialogService>();
|
||||
|
||||
final Map<DialogType, DialogBuilder> builders = {
|
||||
DialogType.addSiswaDialogView: (context, request, completer) =>
|
||||
AddSiswaDialogView(request: request, completer: completer),
|
||||
DialogType.filterDialogView: (context, request, completer) =>
|
||||
FilterDialogView(request: request, completer: completer),
|
||||
DialogType.editStrukrurOrganisasiDialogView:
|
||||
(context, request, completer) => EditStrukrurOrganisasiDialogView(
|
||||
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);
|
||||
}
|
|
@ -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());
|
||||
}
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
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 {
|
||||
|
@ -8,6 +10,8 @@ class CustomBaseViewModel extends BaseViewModel {
|
|||
final navigationService = locator<NavigationService>();
|
||||
final bottomSheetService = locator<BottomSheetService>();
|
||||
final snackbarService = locator<SnackbarService>();
|
||||
final Future<SharedPreferences> prefs = SharedPreferences.getInstance();
|
||||
final otherFunction = locator<OtherFunction>();
|
||||
|
||||
void back() {
|
||||
navigationService.back();
|
||||
|
|
|
@ -1,14 +1,18 @@
|
|||
import 'dart:io';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_dotenv/flutter_dotenv.dart';
|
||||
import 'package:flutter_easyloading/flutter_easyloading.dart';
|
||||
import 'package:stacked_services/stacked_services.dart';
|
||||
|
||||
import 'app/app.dialogs.dart';
|
||||
import 'app/app.locator.dart';
|
||||
import 'app/app.router.dart';
|
||||
import 'app/themes/app_theme.dart';
|
||||
|
||||
Future main() async {
|
||||
WidgetsFlutterBinding.ensureInitialized();
|
||||
HttpOverrides.global = MyHttpOverrides();
|
||||
await dotenv.load(fileName: ".env");
|
||||
await setupAllLocator();
|
||||
runApp(const MyApp());
|
||||
|
@ -21,7 +25,7 @@ class MyApp extends StatelessWidget {
|
|||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return MaterialApp(
|
||||
title: 'Perumahan Mutiara Alga',
|
||||
title: 'Panti Asuhan Aisyiyah Abadi',
|
||||
theme: appTheme,
|
||||
debugShowCheckedModeBanner: false,
|
||||
navigatorKey: StackedService.navigatorKey,
|
||||
|
@ -33,7 +37,16 @@ class MyApp extends StatelessWidget {
|
|||
|
||||
Future<void> setupAllLocator() async {
|
||||
await setupLocator();
|
||||
// setupDialogUi();
|
||||
setupDialogUi();
|
||||
// setupBottomsheetUi();
|
||||
// setupSnackbarUi();
|
||||
}
|
||||
|
||||
class MyHttpOverrides extends HttpOverrides {
|
||||
@override
|
||||
HttpClient createHttpClient(SecurityContext? context) {
|
||||
return super.createHttpClient(context)
|
||||
..badCertificateCallback =
|
||||
(X509Certificate cert, String host, int port) => true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,66 @@
|
|||
class DanaSosialModel {
|
||||
String? idDanaSosial;
|
||||
String? bentuk;
|
||||
String? nama;
|
||||
String? jumlah;
|
||||
String? tanggal;
|
||||
String? keterangan;
|
||||
String? jenisDonasi;
|
||||
String? status;
|
||||
String? jenisBarang;
|
||||
String? satuan;
|
||||
String? jumlahBarang;
|
||||
|
||||
String? createdAt;
|
||||
String? updatedAt;
|
||||
|
||||
DanaSosialModel(
|
||||
{this.idDanaSosial,
|
||||
this.bentuk,
|
||||
this.nama,
|
||||
this.jumlah,
|
||||
this.tanggal,
|
||||
this.keterangan,
|
||||
this.jenisDonasi,
|
||||
this.status,
|
||||
this.jenisBarang,
|
||||
this.satuan,
|
||||
this.jumlahBarang,
|
||||
this.createdAt,
|
||||
this.updatedAt});
|
||||
|
||||
DanaSosialModel.fromJson(Map<String, dynamic> json) {
|
||||
idDanaSosial = json['id_dana_sosial'];
|
||||
bentuk = json['bentuk'];
|
||||
nama = json['nama'] ?? '';
|
||||
jumlah = json['jumlah'];
|
||||
tanggal = json['tanggal'];
|
||||
keterangan = json['ket'] ?? '';
|
||||
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'];
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final Map<String, dynamic> data = <String, dynamic>{};
|
||||
data['id_dana_sosial'] = idDanaSosial;
|
||||
data['bentuk'] = bentuk;
|
||||
data['nama'] = nama;
|
||||
data['jumlah'] = jumlah;
|
||||
data['tanggal'] = tanggal;
|
||||
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;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,80 @@
|
|||
class SiswaModel {
|
||||
String? idSiswa;
|
||||
String? nama;
|
||||
String? tanggalLahir;
|
||||
String? jenisKelamin;
|
||||
String? alamat;
|
||||
String? kemampuan;
|
||||
String? imgUrl;
|
||||
String? createdAt;
|
||||
String? updatedAt;
|
||||
String? tempatLahir;
|
||||
String? noTelpon;
|
||||
String? agama;
|
||||
String? kewarganegaraan;
|
||||
String? pendidikanSd;
|
||||
String? pendidikanSmp;
|
||||
String? pendidikanSma;
|
||||
String? hobi;
|
||||
|
||||
SiswaModel(
|
||||
{this.idSiswa,
|
||||
this.nama,
|
||||
this.tanggalLahir,
|
||||
this.jenisKelamin,
|
||||
this.alamat,
|
||||
this.kemampuan,
|
||||
this.imgUrl,
|
||||
this.createdAt,
|
||||
this.updatedAt,
|
||||
this.tempatLahir,
|
||||
this.noTelpon,
|
||||
this.agama,
|
||||
this.kewarganegaraan,
|
||||
this.pendidikanSd,
|
||||
this.pendidikanSmp,
|
||||
this.pendidikanSma,
|
||||
this.hobi});
|
||||
|
||||
SiswaModel.fromJson(Map<String, dynamic> json) {
|
||||
idSiswa = json['id_siswa'];
|
||||
nama = json['nama'];
|
||||
tanggalLahir = json['tanggal_lahir'];
|
||||
jenisKelamin = json['jenis_kelamin'];
|
||||
alamat = json['alamat'];
|
||||
kemampuan = json['kemampuan'];
|
||||
imgUrl = json['img_url'];
|
||||
createdAt = json['created_at'];
|
||||
updatedAt = json['updated_at'];
|
||||
tempatLahir = json['tempat_lahir'];
|
||||
noTelpon = json['no_telpon'];
|
||||
agama = json['agama'];
|
||||
kewarganegaraan = json['kewarganegaraan'];
|
||||
pendidikanSd = json['pendidikan_sd'];
|
||||
pendidikanSmp = json['pendidikan_smp'];
|
||||
pendidikanSma = json['pendidikan_sma'];
|
||||
hobi = json['hobi'];
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final Map<String, dynamic> data = <String, dynamic>{};
|
||||
data['id_siswa'] = idSiswa;
|
||||
data['nama'] = nama;
|
||||
data['tanggal_lahir'] = tanggalLahir;
|
||||
data['jenis_kelamin'] = jenisKelamin;
|
||||
data['alamat'] = alamat;
|
||||
data['kemampuan'] = kemampuan;
|
||||
data['img_url'] = imgUrl;
|
||||
data['created_at'] = createdAt;
|
||||
data['updated_at'] = updatedAt;
|
||||
data['tempat_lahir'] = tempatLahir;
|
||||
data['no_telpon'] = noTelpon;
|
||||
data['agama'] = agama;
|
||||
data['kewarganegaraan'] = kewarganegaraan;
|
||||
data['pendidikan_sd'] = pendidikanSd;
|
||||
data['pendidikan_smp'] = pendidikanSmp;
|
||||
data['pendidikan_sma'] = pendidikanSma;
|
||||
data['hobi'] = hobi;
|
||||
return data;
|
||||
}
|
||||
}
|
|
@ -1,11 +1,14 @@
|
|||
import 'package:dio/dio.dart';
|
||||
import 'package:flutter_dotenv/flutter_dotenv.dart';
|
||||
|
||||
import '../app/app.logger.dart';
|
||||
|
||||
class MyHttpServices {
|
||||
final log = getLogger('MyHttpServices');
|
||||
final _options = BaseOptions(
|
||||
baseUrl: dotenv.env['api_url']!,
|
||||
connectTimeout: const Duration(seconds: 60),
|
||||
receiveTimeout: const Duration(seconds: 60),
|
||||
connectTimeout: const Duration(seconds: 120),
|
||||
receiveTimeout: const Duration(seconds: 120),
|
||||
);
|
||||
|
||||
late Dio _dio;
|
||||
|
@ -17,7 +20,9 @@ class MyHttpServices {
|
|||
Future<Response> get(String path) async {
|
||||
try {
|
||||
return await _dio.get(path);
|
||||
} on DioError {
|
||||
} on DioError catch (e) {
|
||||
log.e(e.message);
|
||||
log.e(e.response);
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
@ -25,8 +30,32 @@ class MyHttpServices {
|
|||
Future<Response> postWithFormData(String path, FormData formData) async {
|
||||
try {
|
||||
return await _dio.post(path, data: formData);
|
||||
} on DioError {
|
||||
} on DioError catch (e) {
|
||||
log.e(e.message);
|
||||
log.e(e.response!.statusCode);
|
||||
log.e(e.response!.statusMessage);
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
// // delete
|
||||
// Future<Response> delete(String path, FormData data) async {
|
||||
// try {
|
||||
// // log.i('path: $path');
|
||||
// return await _dio.delete(
|
||||
// path,
|
||||
// data: data,
|
||||
// // encoding: Encoding.getByName('utf-8'),
|
||||
// options: Options(
|
||||
// headers: {
|
||||
// 'Content-Type': 'application/x-www-form-urlencoded',
|
||||
// },
|
||||
// ),
|
||||
// );
|
||||
// } on DioError catch (e) {
|
||||
// log.e(e.message);
|
||||
// log.e(e.response);
|
||||
// rethrow;
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
|
|
@ -0,0 +1,106 @@
|
|||
import 'package:intl/intl.dart';
|
||||
|
||||
class OtherFunction {
|
||||
int umur(String tanggalLahir) {
|
||||
// change tanggalLahir to DateTime
|
||||
DateTime date = DateTime.parse(tanggalLahir);
|
||||
// get current date
|
||||
DateTime now = DateTime.now();
|
||||
// get difference in year
|
||||
int year = now.year - date.year;
|
||||
return year;
|
||||
}
|
||||
|
||||
String commaFormat(int number) {
|
||||
final formatter = NumberFormat('#,###');
|
||||
return formatter.format(number);
|
||||
}
|
||||
|
||||
String changeMonth(String month) {
|
||||
switch (month) {
|
||||
case 'Januari':
|
||||
return '01';
|
||||
case 'Februari':
|
||||
return '02';
|
||||
case 'Maret':
|
||||
return '03';
|
||||
case 'April':
|
||||
return '04';
|
||||
case 'Mei':
|
||||
return '05';
|
||||
case 'Juni':
|
||||
return '06';
|
||||
case 'Juli':
|
||||
return '07';
|
||||
case 'Agustus':
|
||||
return '08';
|
||||
case 'September':
|
||||
return '09';
|
||||
case 'Oktober':
|
||||
return '10';
|
||||
case 'November':
|
||||
return '11';
|
||||
case 'Desember':
|
||||
return '12';
|
||||
default:
|
||||
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(' ');
|
||||
}
|
||||
}
|
|
@ -0,0 +1,286 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:stacked/stacked.dart';
|
||||
import 'package:stacked_services/stacked_services.dart';
|
||||
import 'package:validatorless/validatorless.dart';
|
||||
|
||||
import '../../../../../app/themes/app_colors.dart';
|
||||
import '../../../../../app/themes/app_text.dart';
|
||||
import '../../../../widgets/my_textformfield.dart';
|
||||
import './add_siswa_dialog_view_model.dart';
|
||||
|
||||
class DataSiswa {
|
||||
final String? nama;
|
||||
|
||||
DataSiswa({required this.nama, r});
|
||||
}
|
||||
|
||||
class AddSiswaDialogView extends StatelessWidget {
|
||||
final DialogRequest<DataSiswa> request;
|
||||
final Function(DialogResponse) completer;
|
||||
|
||||
const AddSiswaDialogView({
|
||||
Key? key,
|
||||
required DialogRequest request,
|
||||
required this.completer,
|
||||
}) : request = request as DialogRequest<DataSiswa>,
|
||||
super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ViewModelBuilder<AddSiswaDialogViewModel>.reactive(
|
||||
viewModelBuilder: () => AddSiswaDialogViewModel(),
|
||||
onViewModelReady: (AddSiswaDialogViewModel model) async {
|
||||
await model.init();
|
||||
},
|
||||
builder: (
|
||||
BuildContext context,
|
||||
AddSiswaDialogViewModel model,
|
||||
Widget? child,
|
||||
) {
|
||||
return Dialog(
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
),
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
),
|
||||
padding: const EdgeInsets.all(10),
|
||||
child: SingleChildScrollView(
|
||||
child: Form(
|
||||
key: model.formKey,
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text(
|
||||
'Tambah Anak Panti',
|
||||
style: boldTextStyle.copyWith(
|
||||
fontSize: 16,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
// create circle avatar
|
||||
Stack(
|
||||
children: [
|
||||
CircleAvatar(
|
||||
radius: 50,
|
||||
backgroundColor: fontParagraphColor,
|
||||
child: model.imageBytes == null
|
||||
? const Icon(
|
||||
Icons.person,
|
||||
size: 50,
|
||||
color: Colors.white,
|
||||
)
|
||||
: ClipRRect(
|
||||
borderRadius: BorderRadius.circular(50),
|
||||
child: Image.memory(
|
||||
model.imageBytes!,
|
||||
width: 100,
|
||||
height: 100,
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
bottom: 0,
|
||||
right: 0,
|
||||
child: CircleAvatar(
|
||||
radius: 15,
|
||||
backgroundColor: blueColor,
|
||||
child: IconButton(
|
||||
onPressed: () {
|
||||
model.addImage();
|
||||
},
|
||||
icon: const Icon(
|
||||
Icons.add,
|
||||
color: lightColor,
|
||||
size: 15,
|
||||
)),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
MyTextFormField(
|
||||
labelText: 'Nama',
|
||||
controller: model.namaController,
|
||||
validator:
|
||||
Validatorless.required('Nama tidak boleh kosong'),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
MyTextFormField(
|
||||
labelText: 'Tanggal Lahir',
|
||||
controller: model.tanggalLahirController,
|
||||
readOnly: true,
|
||||
validator: Validatorless.required(
|
||||
'Tanggal lahir tidak boleh kosong'),
|
||||
onTap: () {
|
||||
model.changeDate(context);
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
MyTextFormField(
|
||||
labelText: 'Tempat Lahir',
|
||||
controller: model.tempatLahirController,
|
||||
validator: Validatorless.required(
|
||||
'Tempat lahir tidak boleh kosong'),
|
||||
),
|
||||
|
||||
const SizedBox(height: 10),
|
||||
// create dropdown button
|
||||
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.jenisKelamin,
|
||||
onChanged: (String? newValue) {
|
||||
// model.setSelectedJenisKelamin(newValue!);
|
||||
model.log.i(newValue);
|
||||
model.jenisKelamin = newValue!;
|
||||
model.notifyListeners();
|
||||
},
|
||||
items: model.jenisKelaminList.map((String value) {
|
||||
return DropdownMenuItem<String>(
|
||||
value: value,
|
||||
child: Text(
|
||||
value,
|
||||
style: regularTextStyle.copyWith(
|
||||
fontSize: 16,
|
||||
),
|
||||
),
|
||||
);
|
||||
}).toList(),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
MyTextFormField(
|
||||
labelText: 'No. Telepon',
|
||||
controller: model.noTelponController,
|
||||
keyboardType: TextInputType.number,
|
||||
validator: Validatorless.multiple(
|
||||
[
|
||||
Validatorless.required(
|
||||
'No. telepon tidak boleh kosong'),
|
||||
Validatorless.number(
|
||||
'No. telepon harus berupa angka'),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
MyTextFormField(
|
||||
labelText: 'Agama',
|
||||
controller: model.agamaController,
|
||||
keyboardType: TextInputType.emailAddress,
|
||||
validator:
|
||||
Validatorless.required('Agama tidak boleh kosong'),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
MyTextFormField(
|
||||
labelText: 'Kewarganegaraan',
|
||||
controller: model.kewarganegaraanController,
|
||||
keyboardType: TextInputType.emailAddress,
|
||||
validator: Validatorless.required(
|
||||
'Kewarganegaraan tidak boleh kosong'),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
MyTextFormField(
|
||||
labelText: 'Alamat',
|
||||
controller: model.alamatController,
|
||||
maxLines: 2,
|
||||
validator:
|
||||
Validatorless.required('Alamat tidak boleh kosong'),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
MyTextFormField(
|
||||
labelText: 'Pendidikan SD',
|
||||
controller: model.pendidikanSDController,
|
||||
validator: Validatorless.required(
|
||||
'Pendidikan SD tidak boleh kosong'),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
MyTextFormField(
|
||||
labelText: 'Pendidikan SMP',
|
||||
controller: model.pendidikanSMPController,
|
||||
validator: Validatorless.required(
|
||||
'Pendidikan SMP tidak boleh kosong'),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
MyTextFormField(
|
||||
labelText: 'Pendidikan SMA',
|
||||
controller: model.pendidikanSMAController,
|
||||
validator: Validatorless.required(
|
||||
'Pendidikan SMA tidak boleh kosong'),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
MyTextFormField(
|
||||
labelText: 'Kemampuan',
|
||||
controller: model.kemampuanController,
|
||||
maxLines: 4,
|
||||
validator: Validatorless.required(
|
||||
'Kemampuan tidak boleh kosong'),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
MyTextFormField(
|
||||
labelText: "Hobi",
|
||||
controller: model.hobiController,
|
||||
maxLines: 4,
|
||||
validator:
|
||||
Validatorless.required('Hobi tidak boleh kosong'),
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: [
|
||||
TextButton(
|
||||
onPressed: () => completer(
|
||||
DialogResponse(
|
||||
confirmed: false,
|
||||
),
|
||||
),
|
||||
child: const Text(
|
||||
'Batal',
|
||||
style: TextStyle(
|
||||
color: dangerColor,
|
||||
),
|
||||
),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () async {
|
||||
if (model.formKey.currentState!.validate()) {
|
||||
bool res = await model.postData();
|
||||
model.log.i("res: $res");
|
||||
if (res) {
|
||||
completer(
|
||||
DialogResponse(
|
||||
confirmed: true,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
child: const Text(
|
||||
'Simpan',
|
||||
style: TextStyle(
|
||||
color: blueColor,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
)),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,127 @@
|
|||
import 'dart:typed_data';
|
||||
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_holo_date_picker/flutter_holo_date_picker.dart';
|
||||
import 'package:image_picker/image_picker.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 AddSiswaDialogViewModel extends CustomBaseViewModel {
|
||||
final log = getLogger('AddSiswaDialogViewModel');
|
||||
final _httpService = locator<MyHttpServices>();
|
||||
final easyLoading = locator<MyEasyLoading>();
|
||||
List<String> jenisKelaminList = ['Laki-laki', 'Perempuan'];
|
||||
|
||||
String jenisKelamin = 'Laki-laki';
|
||||
|
||||
// image picker
|
||||
String? _imagePath;
|
||||
final ImagePicker _picker = ImagePicker();
|
||||
XFile? imageFile;
|
||||
Uint8List? imageBytes;
|
||||
|
||||
// form and text controller
|
||||
final formKey = GlobalKey<FormState>();
|
||||
|
||||
TextEditingController namaController = TextEditingController();
|
||||
TextEditingController tanggalLahirController = TextEditingController();
|
||||
TextEditingController tempatLahirController = TextEditingController();
|
||||
TextEditingController alamatController = TextEditingController();
|
||||
TextEditingController noTelponController = TextEditingController();
|
||||
TextEditingController agamaController = TextEditingController();
|
||||
TextEditingController kewarganegaraanController = TextEditingController();
|
||||
TextEditingController pendidikanSDController = TextEditingController();
|
||||
TextEditingController pendidikanSMPController = TextEditingController();
|
||||
TextEditingController pendidikanSMAController = TextEditingController();
|
||||
TextEditingController kemampuanController = TextEditingController();
|
||||
TextEditingController hobiController = TextEditingController();
|
||||
|
||||
Future<void> init() async {}
|
||||
|
||||
void changeDate(BuildContext context) async {
|
||||
// get today's date
|
||||
var datePicked = await DatePicker.showSimpleDatePicker(
|
||||
context,
|
||||
initialDate: DateTime(2010),
|
||||
firstDate: DateTime(2000),
|
||||
lastDate: DateTime(2015),
|
||||
dateFormat: "dd-MMMM-yyyy",
|
||||
locale: DateTimePickerLocale.id,
|
||||
looping: true,
|
||||
);
|
||||
|
||||
if (datePicked != null) {
|
||||
String date = datePicked.toString().split(' ')[0];
|
||||
tanggalLahirController.text = date;
|
||||
}
|
||||
}
|
||||
|
||||
void addImage() async {
|
||||
try {
|
||||
final XFile? image = await _picker.pickImage(source: ImageSource.gallery);
|
||||
if (image != null) {
|
||||
imageFile = image;
|
||||
_imagePath = image.path;
|
||||
imageBytes = await image.readAsBytes();
|
||||
|
||||
log.i('image path: $_imagePath');
|
||||
notifyListeners();
|
||||
}
|
||||
} catch (e) {
|
||||
log.e(e);
|
||||
}
|
||||
}
|
||||
|
||||
Future<bool> postData() async {
|
||||
if (imageBytes == null) {
|
||||
easyLoading.showError('Foto belum dipilih');
|
||||
return false;
|
||||
}
|
||||
|
||||
easyLoading.customLoading('Menambahkan data...');
|
||||
try {
|
||||
var formData = FormData.fromMap({
|
||||
'nama': namaController.text,
|
||||
'jenis_kelamin': jenisKelamin,
|
||||
'tanggal_lahir': tanggalLahirController.text,
|
||||
'tempat_lahir': tempatLahirController.text,
|
||||
'alamat': alamatController.text,
|
||||
'no_telpon': noTelponController.text,
|
||||
'agama': agamaController.text,
|
||||
'kewarganegaraan': kewarganegaraanController.text,
|
||||
'pendidikan_sd': pendidikanSDController.text,
|
||||
'pendidikan_smp': pendidikanSMPController.text,
|
||||
'pendidikan_sma': pendidikanSMAController.text,
|
||||
'kemampuan': kemampuanController.text,
|
||||
'hobi': hobiController.text,
|
||||
'foto': await MultipartFile.fromFile(_imagePath!),
|
||||
});
|
||||
|
||||
var response = await _httpService.postWithFormData('siswa', formData);
|
||||
easyLoading.dismissLoading();
|
||||
log.i(response.data);
|
||||
easyLoading.showSuccess('Siswa berhasil ditambahkan');
|
||||
return true;
|
||||
} catch (e) {
|
||||
easyLoading.dismissLoading();
|
||||
snackbarService.showSnackbar(
|
||||
message: 'Terjadi kesalahan',
|
||||
title: 'Gagal',
|
||||
duration: const Duration(seconds: 4),
|
||||
);
|
||||
log.e(e);
|
||||
return false;
|
||||
}
|
||||
|
||||
// completer(
|
||||
// DialogResponse(
|
||||
// confirmed: true,
|
||||
// ),
|
||||
// );
|
||||
}
|
||||
}
|
|
@ -20,10 +20,9 @@ class AdminIndexView extends StatelessWidget {
|
|||
) {
|
||||
return const Scaffold(
|
||||
body: Center(
|
||||
child: Text(
|
||||
'AdminIndexView asdas asda aasdsda a',
|
||||
),
|
||||
),
|
||||
child: CircularProgressIndicator(
|
||||
color: Colors.grey,
|
||||
)),
|
||||
);
|
||||
},
|
||||
);
|
||||
|
|
|
@ -24,60 +24,75 @@ class AdminIndexTrackingView extends StatelessWidget {
|
|||
AdminIndexTrackingViewModel model,
|
||||
Widget? child,
|
||||
) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text(
|
||||
model.header,
|
||||
style: const TextStyle(
|
||||
color: Colors.white,
|
||||
fontSize: 20,
|
||||
return WillPopScope(
|
||||
onWillPop: () async {
|
||||
return false;
|
||||
},
|
||||
child: Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text(
|
||||
model.header,
|
||||
style: const TextStyle(
|
||||
color: Colors.white,
|
||||
fontSize: 20,
|
||||
),
|
||||
),
|
||||
backgroundColor: mainColor,
|
||||
elevation: 0,
|
||||
automaticallyImplyLeading: false,
|
||||
actions: [
|
||||
IconButton(
|
||||
onPressed: () {
|
||||
model.logout(context);
|
||||
},
|
||||
icon: const Icon(Icons.logout, color: Colors.white),
|
||||
),
|
||||
],
|
||||
),
|
||||
body: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 15),
|
||||
child: ExtendedNavigator(
|
||||
navigatorKey: StackedService.nestedNavigationKey(3),
|
||||
router: AdminIndexTrackingViewRouter(),
|
||||
initialRoute: AdminIndexTrackingViewRoutes.danaSosialAdminView,
|
||||
),
|
||||
),
|
||||
backgroundColor: mainColor,
|
||||
elevation: 0,
|
||||
automaticallyImplyLeading: false,
|
||||
),
|
||||
body: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 15),
|
||||
child: ExtendedNavigator(
|
||||
navigatorKey: StackedService.nestedNavigationKey(3),
|
||||
router: AdminIndexTrackingViewRouter(),
|
||||
),
|
||||
),
|
||||
bottomNavigationBar: StylishBottomBar(
|
||||
items: [
|
||||
for (var item in model.bottomNavBarList)
|
||||
BottomBarItem(
|
||||
icon: Icon(item['icon'],
|
||||
color: model.currentIndex ==
|
||||
model.bottomNavBarList.indexOf(item)
|
||||
? sixthGrey
|
||||
: backgroundColor),
|
||||
title: Text(
|
||||
item['name'],
|
||||
style: regularTextStyle.copyWith(
|
||||
color: model.currentIndex ==
|
||||
model.bottomNavBarList.indexOf(item)
|
||||
? sixthGrey
|
||||
: Colors.grey,
|
||||
bottomNavigationBar: StylishBottomBar(
|
||||
items: [
|
||||
for (var item in model.bottomNavBarList)
|
||||
BottomBarItem(
|
||||
icon: Icon(item['icon'],
|
||||
color: model.currentIndex ==
|
||||
model.bottomNavBarList.indexOf(item)
|
||||
? sixthGrey
|
||||
: backgroundColor),
|
||||
title: Text(
|
||||
model.otherFunction.capitalizeEachWord(item['name']),
|
||||
style: regularTextStyle.copyWith(
|
||||
color: model.currentIndex ==
|
||||
model.bottomNavBarList.indexOf(item)
|
||||
? sixthGrey
|
||||
: Colors.grey,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
backgroundColor: model.currentIndex ==
|
||||
model.bottomNavBarList.indexOf(item)
|
||||
? Colors.white
|
||||
: Colors.grey,
|
||||
),
|
||||
backgroundColor:
|
||||
model.currentIndex == model.bottomNavBarList.indexOf(item)
|
||||
? Colors.white
|
||||
: Colors.grey,
|
||||
),
|
||||
],
|
||||
currentIndex: model.currentIndex,
|
||||
hasNotch: true,
|
||||
backgroundColor: mainColor,
|
||||
onTap: (value) {
|
||||
model.handleNavigation(value);
|
||||
},
|
||||
option: BubbleBarOptions(
|
||||
barStyle: BubbleBarStyle.horizotnal,
|
||||
bubbleFillStyle: BubbleFillStyle.fill,
|
||||
opacity: 0.3),
|
||||
],
|
||||
currentIndex: model.currentIndex,
|
||||
hasNotch: true,
|
||||
backgroundColor: mainColor,
|
||||
onTap: (value) {
|
||||
model.handleNavigation(value);
|
||||
},
|
||||
option: BubbleBarOptions(
|
||||
barStyle: BubbleBarStyle.horizotnal,
|
||||
bubbleFillStyle: BubbleFillStyle.fill,
|
||||
opacity: 0.3),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
|
|
|
@ -1,27 +1,40 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:panti_asuhan/app/app.router.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';
|
||||
|
||||
import '../../../app/app.locator.dart';
|
||||
import '../../../app/app.logger.dart';
|
||||
import '../../../app/app.router.dart';
|
||||
|
||||
class AdminIndexTrackingViewModel extends IndexTrackingViewModel {
|
||||
final log = getLogger('AdminIndexTrackingViewModel');
|
||||
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 Sosial', 'icon': Icons.money, 'header': 'Dana Sosial'},
|
||||
{'name': 'Dana', 'icon': Icons.money, 'header': 'Dana Sosial'},
|
||||
// {'name': 'Dana', 'icon': Icons.money, 'header': 'Dana Sosial Khusus'},
|
||||
{
|
||||
'name': 'Profil',
|
||||
'icon': Icons.list_alt_rounded,
|
||||
'icon': Icons.person_4_outlined,
|
||||
'header': 'Profil Panti Asuhan'
|
||||
}
|
||||
},
|
||||
{'name': 'V & M', 'icon': Icons.list_alt_rounded, 'header': 'Visi & Misi'},
|
||||
{'name': 'Sejarah', 'icon': Icons.list_outlined, 'header': 'Sejarah'},
|
||||
{
|
||||
'name': 'S O',
|
||||
'icon': Icons.people_alt_outlined,
|
||||
'header': 'Struktur Organisasi'
|
||||
},
|
||||
];
|
||||
|
||||
List<Map<String, dynamic>> get bottomNavBarList => _bottomNavBarList;
|
||||
|
@ -29,13 +42,23 @@ class AdminIndexTrackingViewModel extends IndexTrackingViewModel {
|
|||
final List<String> _views = [
|
||||
AdminIndexTrackingViewRoutes.dataSiswaView,
|
||||
AdminIndexTrackingViewRoutes.danaSosialAdminView,
|
||||
// AdminIndexTrackingViewRoutes.danaSosialKhususView,
|
||||
AdminIndexTrackingViewRoutes.profilView,
|
||||
AdminIndexTrackingViewRoutes.visiMisiView,
|
||||
AdminIndexTrackingViewRoutes.sejarahView,
|
||||
AdminIndexTrackingViewRoutes.strukturOrganisasiView
|
||||
];
|
||||
|
||||
String header = 'Dana Sosial';
|
||||
|
||||
Future<void> init() async {
|
||||
setIndex(1);
|
||||
// await 2 seconds to make sure the view is loaded
|
||||
// await Future.delayed(const Duration(milliseconds: 500));
|
||||
// _navigationService.navigateTo(
|
||||
// _views[1],
|
||||
// id: 3,
|
||||
// );
|
||||
}
|
||||
|
||||
void handleNavigation(int index) {
|
||||
|
@ -51,4 +74,31 @@ class AdminIndexTrackingViewModel extends IndexTrackingViewModel {
|
|||
id: 3,
|
||||
);
|
||||
}
|
||||
|
||||
logout(BuildContext context) {
|
||||
_dialogService
|
||||
.showConfirmationDialog(
|
||||
title: 'Logout',
|
||||
description: 'Apakah anda yakin ingin logout?',
|
||||
cancelTitle: 'Ya',
|
||||
confirmationTitle: 'Tidak',
|
||||
// barrierDismissible: true,
|
||||
)
|
||||
.then((value) {
|
||||
if (!value!.confirmed) {
|
||||
log.d('logout');
|
||||
_prefs.then((SharedPreferences prefs) {
|
||||
prefs.setBool('isLogin', false);
|
||||
prefs.remove('role');
|
||||
_navigationService.clearStackAndShow(Routes.loginScreenView);
|
||||
});
|
||||
} else {
|
||||
// _navigationService.back();
|
||||
// close dialog
|
||||
Navigator.pop(context);
|
||||
// Navigator.of(StackedService.navigatorKey! as BuildContext).pop();
|
||||
// log.d('cancel logout');
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:panti_asuhan/app/themes/app_colors.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_view_model.dart';
|
||||
|
||||
class DanaSosialAdminView extends StatelessWidget {
|
||||
|
@ -21,14 +22,114 @@ class DanaSosialAdminView extends StatelessWidget {
|
|||
Widget? child,
|
||||
) {
|
||||
return Scaffold(
|
||||
body: Column(
|
||||
body: SingleChildScrollView(
|
||||
child: Column(
|
||||
children: [
|
||||
const SizedBox(height: 10),
|
||||
Text(
|
||||
"Laporan Harian",
|
||||
style:
|
||||
boldTextStyle.copyWith(fontSize: 15, color: Colors.black),
|
||||
),
|
||||
Container(
|
||||
padding:
|
||||
const EdgeInsets.symmetric(horizontal: 15, vertical: 10),
|
||||
width: double.infinity,
|
||||
padding: const EdgeInsets.all(10),
|
||||
height: MediaQuery.of(context).size.height * 0.45,
|
||||
decoration: BoxDecoration(
|
||||
color: mainColor,
|
||||
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: 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(
|
||||
|
@ -41,84 +142,758 @@ class DanaSosialAdminView extends StatelessWidget {
|
|||
],
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
'Dana Sosial Bulan Ini',
|
||||
style: boldTextStyle.copyWith(
|
||||
color: Colors.white,
|
||||
fontSize: 20,
|
||||
),
|
||||
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: [
|
||||
Text(
|
||||
'Total Dana Sosial',
|
||||
style: regularTextStyle.copyWith(
|
||||
color: Colors.white,
|
||||
fontSize: 15,
|
||||
),
|
||||
const Text(
|
||||
'Total Pengeluaran :',
|
||||
),
|
||||
const Expanded(child: SizedBox()),
|
||||
Text(
|
||||
'Rp. 1.000.000',
|
||||
style: regularTextStyle.copyWith(
|
||||
color: Colors.white,
|
||||
fontSize: 15,
|
||||
),
|
||||
),
|
||||
'Rp. ${OtherFunction().commaFormat(model.totalOutcome)}',
|
||||
)
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 25),
|
||||
Expanded(
|
||||
child: Container(
|
||||
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: ListView.builder(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 15, vertical: 10),
|
||||
itemCount: 20,
|
||||
itemBuilder: (context, index) {
|
||||
return Card(
|
||||
child: GestureDetector(
|
||||
onTap: () {
|
||||
model.log.i('Card $index tapped');
|
||||
},
|
||||
child: ListTile(
|
||||
title: Text('1/02/15 - 10.00 am',
|
||||
style: boldTextStyle.copyWith(
|
||||
fontSize: 13, color: mainColor)),
|
||||
subtitle: Text('Progress $index'),
|
||||
trailing: Text('Pembangunan $index'),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 30,
|
||||
),
|
||||
],
|
||||
),
|
||||
floatingActionButton: const FloatingActionButton(
|
||||
onPressed: null,
|
||||
child: Icon(Icons.add),
|
||||
));
|
||||
),
|
||||
floatingActionButton: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: [
|
||||
if (model.role == 'admin')
|
||||
FloatingActionButton(
|
||||
mini: true,
|
||||
heroTag: 'btn11',
|
||||
onPressed: () {
|
||||
model.goToTambahDanaSosial();
|
||||
},
|
||||
child: const Icon(Icons.add),
|
||||
),
|
||||
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,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, DanaSosialAdminViewModel viewModel) {
|
||||
return ListView.builder(
|
||||
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'
|
||||
? 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<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,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,471 @@
|
|||
import 'package:panti_asuhan/app/core/custom_base_view_model.dart';
|
||||
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';
|
||||
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 DanaSosialAdminViewModel extends CustomBaseViewModel {
|
||||
final log = getLogger('DanaSosialAdminViewModel');
|
||||
Future<void> init() async {}
|
||||
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();
|
||||
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?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');
|
||||
// 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));
|
||||
}
|
||||
}
|
||||
|
||||
changeByDate(danaSosialModelList);
|
||||
getTahunan();
|
||||
notifyListeners();
|
||||
// log.i(danaSosialModelList.length);
|
||||
} catch (e) {
|
||||
log.e(e);
|
||||
} 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);
|
||||
}
|
||||
|
||||
getFilter(String sql) async {
|
||||
setBusy(true);
|
||||
easyLoading.showLoading();
|
||||
FormData formData = FormData.fromMap({
|
||||
'sql': sql,
|
||||
});
|
||||
try {
|
||||
var response = await _httpService.postWithFormData(
|
||||
'filter_dana',
|
||||
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);
|
||||
changeByDate(danaSosialModelList);
|
||||
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 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,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
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 {
|
||||
await _httpService.postWithFormData(
|
||||
'hapus_dana_sosial',
|
||||
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;
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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,
|
||||
),
|
||||
],
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -1,6 +1,9 @@
|
|||
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 './data_siswa_view_model.dart';
|
||||
|
||||
class DataSiswaView extends StatelessWidget {
|
||||
|
@ -18,12 +21,135 @@ class DataSiswaView extends StatelessWidget {
|
|||
DataSiswaViewModel model,
|
||||
Widget? child,
|
||||
) {
|
||||
return const Scaffold(
|
||||
body: Center(
|
||||
child: Text(
|
||||
'DataSiswaView',
|
||||
),
|
||||
return Scaffold(
|
||||
body: Column(
|
||||
children: [
|
||||
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: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
'Total Anak Panti',
|
||||
style: regularTextStyle.copyWith(
|
||||
color: Colors.white,
|
||||
fontSize: 15,
|
||||
),
|
||||
),
|
||||
Text(
|
||||
'${model.jumlahSiswa} orang',
|
||||
style: regularTextStyle.copyWith(
|
||||
color: Colors.white,
|
||||
fontSize: 15,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 25),
|
||||
Expanded(
|
||||
child: Container(
|
||||
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.siswaModelList.isEmpty)
|
||||
? Center(
|
||||
child: Text(
|
||||
'Tidak ada data',
|
||||
style: boldTextStyle.copyWith(
|
||||
fontSize: 20,
|
||||
),
|
||||
),
|
||||
)
|
||||
: // ListView.builder(
|
||||
ListView.builder(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 15, vertical: 10),
|
||||
itemCount: model.siswaModelList.length,
|
||||
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.otherFunction.capitalizeEachWord(
|
||||
model.siswaModelList[index].nama!),
|
||||
style: boldTextStyle.copyWith(
|
||||
fontSize: 13, color: mainColor)),
|
||||
subtitle: Text(
|
||||
'Umur : ${OtherFunction().umur(model.siswaModelList[index].tanggalLahir ?? '')}'),
|
||||
// circle avatar
|
||||
trailing: GestureDetector(
|
||||
onTap: () {
|
||||
model.log.i(
|
||||
'Edit${model.siswaModelList[index].idSiswa!}');
|
||||
model.goToEditSiswa(int.parse(model
|
||||
.siswaModelList[index].idSiswa!));
|
||||
},
|
||||
child: Container(
|
||||
width: 50,
|
||||
height: 50,
|
||||
decoration: BoxDecoration(
|
||||
color: mainColor,
|
||||
borderRadius: BorderRadius.circular(50),
|
||||
),
|
||||
child: const Icon(
|
||||
Icons.person,
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
)),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
floatingActionButton: model.role == 'admin'
|
||||
? FloatingActionButton(
|
||||
onPressed: () {
|
||||
model.addSiswa();
|
||||
},
|
||||
child: const Icon(Icons.add),
|
||||
)
|
||||
: null,
|
||||
);
|
||||
},
|
||||
);
|
||||
|
|
|
@ -1,5 +1,88 @@
|
|||
import 'package:panti_asuhan/app/core/custom_base_view_model.dart';
|
||||
import 'package:panti_asuhan/ui/views/admin_index_tracking/edit_siswa/edit_siswa_view.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/core/custom_base_view_model.dart';
|
||||
import '../../../../model/siswa_model.dart';
|
||||
import '../../../../services/http_services.dart';
|
||||
import '../../../../services/my_easyloading.dart';
|
||||
import '../add_siswa_dialog/add_siswa_dialog/add_siswa_dialog_view.dart';
|
||||
|
||||
class DataSiswaViewModel extends CustomBaseViewModel {
|
||||
Future<void> init() async {}
|
||||
final log = getLogger('DataSiswaViewModel');
|
||||
final _httpService = locator<MyHttpServices>();
|
||||
final easyLoading = locator<MyEasyLoading>();
|
||||
|
||||
List<SiswaModel> siswaModelList = [];
|
||||
|
||||
int jumlahSiswa = 0;
|
||||
|
||||
String? role;
|
||||
|
||||
Future<void> init() async {
|
||||
await getData();
|
||||
await getJumlahSiswa();
|
||||
prefs.then((SharedPreferences prefs) {
|
||||
role = prefs.getString('role');
|
||||
});
|
||||
}
|
||||
|
||||
getJumlahSiswa() async {
|
||||
setBusy(true);
|
||||
easyLoading.showLoading();
|
||||
try {
|
||||
var response = await _httpService.get('jumlah_siswa');
|
||||
log.i(response.data['data']);
|
||||
jumlahSiswa = int.parse(response.data['data']['jumlah']);
|
||||
} catch (e) {
|
||||
log.e(e);
|
||||
} finally {
|
||||
setBusy(false);
|
||||
easyLoading.dismissLoading();
|
||||
}
|
||||
}
|
||||
|
||||
getData() async {
|
||||
setBusy(true);
|
||||
easyLoading.showLoading();
|
||||
try {
|
||||
var response = await _httpService.get('siswa');
|
||||
log.i(response.data);
|
||||
siswaModelList = [];
|
||||
|
||||
var datanya = response.data['data'];
|
||||
// log.i(datanya.length);
|
||||
if (datanya.length > 0) {
|
||||
for (var item in datanya) {
|
||||
siswaModelList.add(SiswaModel.fromJson(item));
|
||||
}
|
||||
}
|
||||
|
||||
setBusy(false);
|
||||
notifyListeners();
|
||||
log.i(siswaModelList);
|
||||
} catch (e) {
|
||||
log.e(e);
|
||||
} finally {
|
||||
setBusy(false);
|
||||
easyLoading.dismissLoading();
|
||||
}
|
||||
}
|
||||
|
||||
void addSiswa() async {
|
||||
final res = await dialogService.showCustomDialog(
|
||||
variant: DialogType.addSiswaDialogView,
|
||||
data: DataSiswa(nama: null),
|
||||
);
|
||||
|
||||
if (res?.confirmed != true) return;
|
||||
siswaModelList = [];
|
||||
await getData();
|
||||
}
|
||||
|
||||
goToEditSiswa(int idSiswa) async {
|
||||
navigationService.navigateToView(EditSiswaView(idSiswa: idSiswa));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,315 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:panti_asuhan/app/themes/app_colors.dart';
|
||||
import 'package:panti_asuhan/app/themes/app_text.dart';
|
||||
import 'package:panti_asuhan/ui/widgets/my_textformfield.dart';
|
||||
import 'package:stacked/stacked.dart';
|
||||
import 'package:stacked_services/stacked_services.dart';
|
||||
import 'package:validatorless/validatorless.dart';
|
||||
|
||||
import './edit_dialog_siswa_view_model.dart';
|
||||
|
||||
class EditDialogSiswaView extends StatelessWidget {
|
||||
final DialogRequest request;
|
||||
final Function(DialogResponse) completer;
|
||||
|
||||
const EditDialogSiswaView({
|
||||
Key? key,
|
||||
required this.request,
|
||||
required this.completer,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ViewModelBuilder<EditDialogSiswaViewModel>.reactive(
|
||||
viewModelBuilder: () => EditDialogSiswaViewModel(),
|
||||
onViewModelReady: (EditDialogSiswaViewModel model) async {
|
||||
await model.init(request.data);
|
||||
},
|
||||
builder: (
|
||||
BuildContext context,
|
||||
EditDialogSiswaViewModel model,
|
||||
Widget? child,
|
||||
) {
|
||||
return Dialog(
|
||||
child: Container(
|
||||
padding: const EdgeInsets.all(20),
|
||||
decoration: const BoxDecoration(
|
||||
borderRadius: BorderRadius.only(
|
||||
topLeft: Radius.circular(10),
|
||||
topRight: Radius.circular(10),
|
||||
),
|
||||
),
|
||||
child: SingleChildScrollView(
|
||||
child: Form(
|
||||
key: model.formKey,
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
const Center(
|
||||
child: Text(
|
||||
'Edit Data Anak Panti',
|
||||
style: boldTextStyle,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
Text(
|
||||
' Nama',
|
||||
style: regularTextStyle.copyWith(
|
||||
fontSize: 12,
|
||||
color: mainColor,
|
||||
),
|
||||
),
|
||||
MyTextFormField(
|
||||
hintText: 'Masukkan Nama',
|
||||
controller: model.namaController,
|
||||
validator:
|
||||
Validatorless.required('Nama tidak boleh kosong'),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
Text(
|
||||
' Tanggal Lahir',
|
||||
style: regularTextStyle.copyWith(
|
||||
fontSize: 12,
|
||||
color: mainColor,
|
||||
),
|
||||
),
|
||||
MyTextFormField(
|
||||
controller: model.tanggalLahirController,
|
||||
readOnly: true,
|
||||
validator: Validatorless.required(
|
||||
'Tanggal lahir tidak boleh kosong'),
|
||||
onTap: () {
|
||||
model.changeDate(context);
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
Text(
|
||||
' Tempat Lahir',
|
||||
style: regularTextStyle.copyWith(
|
||||
fontSize: 12,
|
||||
color: mainColor,
|
||||
),
|
||||
),
|
||||
MyTextFormField(
|
||||
hintText: 'Masukkan Tempat Lahir',
|
||||
controller: model.tempatLahirController,
|
||||
validator: Validatorless.required(
|
||||
'Tempat lahir tidak boleh kosong'),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
Text(
|
||||
' Jenis Kelamin',
|
||||
style: regularTextStyle.copyWith(
|
||||
fontSize: 12,
|
||||
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.jenisKelamin,
|
||||
onChanged: (String? newValue) {
|
||||
// model.setSelectedJenisKelamin(newValue!);
|
||||
model.log.i(newValue);
|
||||
model.jenisKelamin = newValue!;
|
||||
model.notifyListeners();
|
||||
},
|
||||
items: model.jenisKelaminList.map((String value) {
|
||||
return DropdownMenuItem<String>(
|
||||
value: value,
|
||||
child: Text(
|
||||
value,
|
||||
style: regularTextStyle.copyWith(
|
||||
fontSize: 16,
|
||||
),
|
||||
),
|
||||
);
|
||||
}).toList(),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
Text(
|
||||
' No. Telepon',
|
||||
style: regularTextStyle.copyWith(
|
||||
fontSize: 12,
|
||||
color: mainColor,
|
||||
),
|
||||
),
|
||||
MyTextFormField(
|
||||
hintText: 'Masukkan No. Telepon',
|
||||
controller: model.noTelponController,
|
||||
validator: Validatorless.multiple(
|
||||
[
|
||||
Validatorless.required(
|
||||
'No. telepon tidak boleh kosong'),
|
||||
Validatorless.number(
|
||||
'No. telepon harus berupa angka'),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
Text(
|
||||
' Agama',
|
||||
style: regularTextStyle.copyWith(
|
||||
fontSize: 12,
|
||||
color: mainColor,
|
||||
),
|
||||
),
|
||||
MyTextFormField(
|
||||
controller: model.agamaController,
|
||||
validator:
|
||||
Validatorless.required('Agama tidak boleh kosong'),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
Text(
|
||||
' Kewarganegaraan',
|
||||
style: regularTextStyle.copyWith(
|
||||
fontSize: 12,
|
||||
color: mainColor,
|
||||
),
|
||||
),
|
||||
MyTextFormField(
|
||||
controller: model.kewarganegaraanController,
|
||||
validator: Validatorless.required(
|
||||
'Kewarganegaraan tidak boleh kosong'),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
Text(
|
||||
' Alamat',
|
||||
style: regularTextStyle.copyWith(
|
||||
fontSize: 12,
|
||||
color: mainColor,
|
||||
),
|
||||
),
|
||||
MyTextFormField(
|
||||
controller: model.alamatController,
|
||||
maxLines: 2,
|
||||
validator:
|
||||
Validatorless.required('Alamat tidak boleh kosong'),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
Text(
|
||||
' Pendidikan SD',
|
||||
style: regularTextStyle.copyWith(
|
||||
fontSize: 12,
|
||||
color: mainColor,
|
||||
),
|
||||
),
|
||||
MyTextFormField(
|
||||
controller: model.pendidikanSDController,
|
||||
validator: Validatorless.required(
|
||||
'Pendidikan SD tidak boleh kosong'),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
Text(
|
||||
' Pendidikan SMP',
|
||||
style: regularTextStyle.copyWith(
|
||||
fontSize: 12,
|
||||
color: mainColor,
|
||||
),
|
||||
),
|
||||
MyTextFormField(
|
||||
controller: model.pendidikanSMPController,
|
||||
validator: Validatorless.required(
|
||||
'Pendidikan SMP tidak boleh kosong'),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
Text(
|
||||
' Pendidikan SMA',
|
||||
style: regularTextStyle.copyWith(
|
||||
fontSize: 12,
|
||||
color: mainColor,
|
||||
),
|
||||
),
|
||||
MyTextFormField(
|
||||
controller: model.pendidikanSMAController,
|
||||
validator: Validatorless.required(
|
||||
'Pendidikan SMA tidak boleh kosong'),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
Text(
|
||||
' Kemampuan',
|
||||
style: regularTextStyle.copyWith(
|
||||
fontSize: 12,
|
||||
color: mainColor,
|
||||
),
|
||||
),
|
||||
MyTextFormField(
|
||||
controller: model.kemampuanController,
|
||||
maxLines: 4,
|
||||
validator: Validatorless.required(
|
||||
'Kemampuan tidak boleh kosong'),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
Text(
|
||||
' Hobi',
|
||||
style: regularTextStyle.copyWith(
|
||||
fontSize: 12,
|
||||
color: mainColor,
|
||||
),
|
||||
),
|
||||
MyTextFormField(
|
||||
controller: model.hobiController,
|
||||
maxLines: 4,
|
||||
validator:
|
||||
Validatorless.required('Hobi tidak boleh kosong'),
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: [
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
completer(DialogResponse(confirmed: false));
|
||||
},
|
||||
child: const Text(
|
||||
'Batal',
|
||||
style: TextStyle(
|
||||
color: dangerColor,
|
||||
),
|
||||
),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () async {
|
||||
if (model.formKey.currentState!.validate()) {
|
||||
bool res = await model.updateSiswa();
|
||||
|
||||
if (res) {
|
||||
// ignore: use_build_context_synchronously
|
||||
Navigator.pop(context);
|
||||
completer(DialogResponse(confirmed: true));
|
||||
}
|
||||
|
||||
// completer(DialogResponse(confirmed: true));
|
||||
}
|
||||
},
|
||||
child: const Text(
|
||||
'Update',
|
||||
style: TextStyle(
|
||||
color: blueColor,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,108 @@
|
|||
import 'package:dio/dio.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter_holo_date_picker/flutter_holo_date_picker.dart';
|
||||
|
||||
import '../../../../../app/app.locator.dart';
|
||||
import '../../../../../app/app.logger.dart';
|
||||
import '../../../../../app/core/custom_base_view_model.dart';
|
||||
import '../../../../../model/siswa_model.dart';
|
||||
import '../../../../../services/http_services.dart';
|
||||
import '../../../../../services/my_easyloading.dart';
|
||||
|
||||
class EditDialogSiswaViewModel extends CustomBaseViewModel {
|
||||
final log = getLogger('EditDialogSiswaViewModel');
|
||||
final easyLoading = locator<MyEasyLoading>();
|
||||
final _httpService = locator<MyHttpServices>();
|
||||
SiswaModel? siswaModel;
|
||||
String jenisKelamin = 'Laki-laki';
|
||||
List<String> jenisKelaminList = ['Laki-laki', 'Perempuan'];
|
||||
|
||||
TextEditingController namaController = TextEditingController();
|
||||
TextEditingController tanggalLahirController = TextEditingController();
|
||||
TextEditingController tempatLahirController = TextEditingController();
|
||||
TextEditingController alamatController = TextEditingController();
|
||||
TextEditingController noTelponController = TextEditingController();
|
||||
TextEditingController agamaController = TextEditingController();
|
||||
TextEditingController kewarganegaraanController = TextEditingController();
|
||||
TextEditingController pendidikanSDController = TextEditingController();
|
||||
TextEditingController pendidikanSMPController = TextEditingController();
|
||||
TextEditingController pendidikanSMAController = TextEditingController();
|
||||
TextEditingController kemampuanController = TextEditingController();
|
||||
TextEditingController hobiController = TextEditingController();
|
||||
final formKey = GlobalKey<FormState>();
|
||||
|
||||
Future<void> init(data) async {
|
||||
log.i('data: $data');
|
||||
setBusy(true);
|
||||
siswaModel = data;
|
||||
notifyListeners();
|
||||
setBusy(false);
|
||||
namaController.text = siswaModel!.nama!;
|
||||
tanggalLahirController.text = siswaModel!.tanggalLahir!;
|
||||
tempatLahirController.text = siswaModel!.tempatLahir!;
|
||||
alamatController.text = siswaModel!.alamat!;
|
||||
noTelponController.text = siswaModel!.noTelpon!;
|
||||
agamaController.text = siswaModel!.agama!;
|
||||
kewarganegaraanController.text = siswaModel!.kewarganegaraan!;
|
||||
pendidikanSDController.text = siswaModel!.pendidikanSd!;
|
||||
pendidikanSMPController.text = siswaModel!.pendidikanSmp!;
|
||||
pendidikanSMAController.text = siswaModel!.pendidikanSma!;
|
||||
kemampuanController.text = siswaModel!.kemampuan!;
|
||||
hobiController.text = siswaModel!.hobi!;
|
||||
|
||||
jenisKelamin = siswaModel!.jenisKelamin!;
|
||||
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
void changeDate(BuildContext context) async {
|
||||
// get today's date
|
||||
var datePicked = await DatePicker.showSimpleDatePicker(
|
||||
context,
|
||||
initialDate: DateTime(2010),
|
||||
firstDate: DateTime(2000),
|
||||
lastDate: DateTime(2015),
|
||||
dateFormat: "dd-MMMM-yyyy",
|
||||
locale: DateTimePickerLocale.id,
|
||||
looping: true,
|
||||
);
|
||||
|
||||
if (datePicked != null) {
|
||||
String date = datePicked.toString().split(' ')[0];
|
||||
tanggalLahirController.text = date;
|
||||
}
|
||||
}
|
||||
|
||||
Future<bool> updateSiswa() async {
|
||||
setBusy(true);
|
||||
easyLoading.customLoading('Updating data...');
|
||||
|
||||
try {
|
||||
var formData = FormData.fromMap({
|
||||
'id': siswaModel!.idSiswa,
|
||||
'nama': namaController.text,
|
||||
'tanggal_lahir': tanggalLahirController.text,
|
||||
'tempat_lahir': tempatLahirController.text,
|
||||
'jenis_kelamin': jenisKelamin,
|
||||
'alamat': alamatController.text,
|
||||
'no_telpon': noTelponController.text,
|
||||
'agama': agamaController.text,
|
||||
'kewarganegaraan': kewarganegaraanController.text,
|
||||
'pendidikan_sd': pendidikanSDController.text,
|
||||
'pendidikan_smp': pendidikanSMPController.text,
|
||||
'pendidikan_sma': pendidikanSMAController.text,
|
||||
'kemampuan': kemampuanController.text,
|
||||
'hobi': hobiController.text,
|
||||
});
|
||||
await _httpService.postWithFormData('siswa_edit', formData);
|
||||
snackbarService.showSnackbar(message: 'Data berhasil diupdate');
|
||||
return true;
|
||||
} catch (e) {
|
||||
log.e(e);
|
||||
return false;
|
||||
} finally {
|
||||
easyLoading.dismissLoading();
|
||||
setBusy(false);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,311 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_dotenv/flutter_dotenv.dart';
|
||||
import 'package:stacked/stacked.dart';
|
||||
import 'package:validatorless/validatorless.dart';
|
||||
|
||||
import '../../../../app/themes/app_colors.dart';
|
||||
import '../../../widgets/my_textformfield.dart';
|
||||
import './edit_siswa_view_model.dart';
|
||||
|
||||
class EditSiswaView extends StatelessWidget {
|
||||
final int idSiswa;
|
||||
|
||||
const EditSiswaView({required this.idSiswa, Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ViewModelBuilder<EditSiswaViewModel>.reactive(
|
||||
viewModelBuilder: () => EditSiswaViewModel(),
|
||||
onViewModelReady: (EditSiswaViewModel model) async {
|
||||
await model.init(
|
||||
idSiswa,
|
||||
);
|
||||
},
|
||||
builder: (
|
||||
BuildContext context,
|
||||
EditSiswaViewModel model,
|
||||
Widget? child,
|
||||
) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: const Text(
|
||||
"Informasi Data Anak Panti",
|
||||
style: TextStyle(
|
||||
color: Colors.white,
|
||||
fontSize: 20,
|
||||
),
|
||||
),
|
||||
backgroundColor: mainColor,
|
||||
elevation: 0,
|
||||
// back button color to white
|
||||
iconTheme: const IconThemeData(color: Colors.white),
|
||||
),
|
||||
body: Padding(
|
||||
padding: const EdgeInsets.all(20.0),
|
||||
child: SingleChildScrollView(
|
||||
child: Stack(
|
||||
children: [
|
||||
Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
Center(
|
||||
child: CircleAvatar(
|
||||
radius: 50,
|
||||
backgroundColor: fontParagraphColor,
|
||||
backgroundImage: model.siswaModel != null
|
||||
? NetworkImage(
|
||||
'${dotenv.env['url']}${model.siswaModel!.imgUrl}',
|
||||
)
|
||||
: null,
|
||||
child: model.siswaModel == null
|
||||
? const Icon(
|
||||
Icons.person,
|
||||
size: 50,
|
||||
color: Colors.white,
|
||||
)
|
||||
: null,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
MyTextFormField(
|
||||
labelText: 'Nama',
|
||||
controller: model.namaController,
|
||||
validator:
|
||||
Validatorless.required('Nama tidak boleh kosong'),
|
||||
enabled: false,
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
MyTextFormField(
|
||||
labelText: 'Tanggal Lahir',
|
||||
controller: model.tanggalLahirController,
|
||||
readOnly: true,
|
||||
validator: Validatorless.required(
|
||||
'Tanggal lahir tidak boleh kosong'),
|
||||
enabled: false,
|
||||
onTap: () {
|
||||
// model.changeDate(context);
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
MyTextFormField(
|
||||
labelText: 'Tempat Lahir',
|
||||
controller: model.tempatLahirController,
|
||||
enabled: false,
|
||||
validator: Validatorless.required(
|
||||
'Tempat lahir tidak boleh kosong'),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
// create dropdown button
|
||||
MyTextFormField(
|
||||
labelText: 'Jenis Kelamin',
|
||||
controller: model.jkController,
|
||||
enabled: false,
|
||||
validator: Validatorless.required(
|
||||
'Pendidikan SMP tidak boleh kosong'),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
MyTextFormField(
|
||||
labelText: 'No. Telepon',
|
||||
controller: model.noTelponController,
|
||||
enabled: false,
|
||||
keyboardType: TextInputType.number,
|
||||
validator: Validatorless.multiple(
|
||||
[
|
||||
Validatorless.required(
|
||||
'No. telepon tidak boleh kosong'),
|
||||
Validatorless.number(
|
||||
'No. telepon harus berupa angka'),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
MyTextFormField(
|
||||
labelText: 'Agama',
|
||||
controller: model.agamaController,
|
||||
enabled: false,
|
||||
keyboardType: TextInputType.emailAddress,
|
||||
validator:
|
||||
Validatorless.required('Agama tidak boleh kosong'),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
MyTextFormField(
|
||||
labelText: 'Kewarganegaraan',
|
||||
controller: model.kewarganegaraanController,
|
||||
enabled: false,
|
||||
keyboardType: TextInputType.emailAddress,
|
||||
validator: Validatorless.required(
|
||||
'Kewarganegaraan tidak boleh kosong'),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
MyTextFormField(
|
||||
labelText: 'Alamat',
|
||||
controller: model.alamatController,
|
||||
enabled: false,
|
||||
maxLines: 2,
|
||||
validator:
|
||||
Validatorless.required('Alamat tidak boleh kosong'),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
MyTextFormField(
|
||||
labelText: 'Pendidikan SD',
|
||||
controller: model.pendidikanSDController,
|
||||
enabled: false,
|
||||
validator: Validatorless.required(
|
||||
'Pendidikan SD tidak boleh kosong'),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
MyTextFormField(
|
||||
labelText: 'Pendidikan SMP',
|
||||
controller: model.pendidikanSMPController,
|
||||
enabled: false,
|
||||
validator: Validatorless.required(
|
||||
'Pendidikan SMP tidak boleh kosong'),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
MyTextFormField(
|
||||
labelText: 'Pendidikan SMA',
|
||||
controller: model.pendidikanSMAController,
|
||||
enabled: false,
|
||||
validator: Validatorless.required(
|
||||
'Pendidikan SMA tidak boleh kosong'),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
MyTextFormField(
|
||||
labelText: 'Kemampuan',
|
||||
controller: model.kemampuanController,
|
||||
enabled: false,
|
||||
maxLines: 4,
|
||||
validator: Validatorless.required(
|
||||
'Kemampuan tidak boleh kosong'),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
MyTextFormField(
|
||||
labelText: "Hobi",
|
||||
controller: model.hobiController,
|
||||
enabled: false,
|
||||
maxLines: 4,
|
||||
validator:
|
||||
Validatorless.required('Hobi tidak boleh kosong'),
|
||||
),
|
||||
// Row(
|
||||
// mainAxisAlignment: MainAxisAlignment.end,
|
||||
// children: [
|
||||
// TextButton(
|
||||
// onPressed: () {},
|
||||
// child: const Text(
|
||||
// 'Batal',
|
||||
// style: TextStyle(
|
||||
// color: dangerColor,
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// TextButton(
|
||||
// onPressed: () async {
|
||||
// // if (model.formKey.currentState!.validate()) {
|
||||
// // bool res = await model.postData();
|
||||
// // model.log.i("res: $res");
|
||||
// // if (res) {
|
||||
// // completer(
|
||||
// // DialogResponse(
|
||||
// // confirmed: true,
|
||||
// // ),
|
||||
// // );
|
||||
// // }
|
||||
// // }
|
||||
// },
|
||||
// child: const Text(
|
||||
// 'Simpan',
|
||||
// style: TextStyle(
|
||||
// color: blueColor,
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
],
|
||||
),
|
||||
model.role == 'admin'
|
||||
? Positioned(
|
||||
top: 0,
|
||||
right: 45,
|
||||
// create a edit rounded button
|
||||
child: Container(
|
||||
alignment: Alignment.center,
|
||||
height: 30,
|
||||
width: 30,
|
||||
decoration: BoxDecoration(
|
||||
color: blueColor,
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
),
|
||||
child: IconButton(
|
||||
onPressed: () {
|
||||
// model.changeEdit();
|
||||
model.editData();
|
||||
},
|
||||
icon: const Icon(
|
||||
Icons.edit,
|
||||
color: Colors.white,
|
||||
size: 13,
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
: const SizedBox(),
|
||||
model.role == 'admin'
|
||||
? Positioned(
|
||||
top: 0,
|
||||
right: 0,
|
||||
// create a close rounded button
|
||||
child: Container(
|
||||
alignment: Alignment.center,
|
||||
height: 30,
|
||||
width: 30,
|
||||
decoration: BoxDecoration(
|
||||
color: dangerColor,
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
),
|
||||
child: IconButton(
|
||||
onPressed: () {
|
||||
// model.changeEdit();
|
||||
model.dialogService
|
||||
.showDialog(
|
||||
title: 'Hapus Data',
|
||||
description:
|
||||
'Apakah anda yakin ingin menghapus data ini?',
|
||||
buttonTitle: 'Hapus',
|
||||
cancelTitle: 'Batal',
|
||||
buttonTitleColor: dangerColor,
|
||||
cancelTitleColor: mainColor,
|
||||
)
|
||||
.then((value) {
|
||||
if (value!.confirmed) {
|
||||
model.deleteData();
|
||||
// close dialog
|
||||
Navigator.pop(context);
|
||||
// model.navigationService.clearTillFirstAndShow(
|
||||
// Routes.splashScreenView);
|
||||
}
|
||||
});
|
||||
|
||||
// model.deleteData();
|
||||
},
|
||||
icon: const Icon(
|
||||
Icons.delete_forever,
|
||||
color: Colors.white,
|
||||
size: 15,
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
: const SizedBox(),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,118 @@
|
|||
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/core/custom_base_view_model.dart';
|
||||
import '../../../../model/siswa_model.dart';
|
||||
import '../../../../services/http_services.dart';
|
||||
import '../../../../services/my_easyloading.dart';
|
||||
|
||||
class EditSiswaViewModel extends CustomBaseViewModel {
|
||||
final log = getLogger('EditSiswaViewModel');
|
||||
final _httpService = locator<MyHttpServices>();
|
||||
final easyLoading = locator<MyEasyLoading>();
|
||||
String? role;
|
||||
SiswaModel? siswaModel;
|
||||
List<String> jenisKelaminList = ['Laki-laki', 'Perempuan'];
|
||||
String jenisKelamin = 'Laki-laki';
|
||||
|
||||
TextEditingController namaController = TextEditingController();
|
||||
TextEditingController tanggalLahirController = TextEditingController();
|
||||
TextEditingController tempatLahirController = TextEditingController();
|
||||
TextEditingController alamatController = TextEditingController();
|
||||
TextEditingController noTelponController = TextEditingController();
|
||||
TextEditingController agamaController = TextEditingController();
|
||||
TextEditingController kewarganegaraanController = TextEditingController();
|
||||
TextEditingController pendidikanSDController = TextEditingController();
|
||||
TextEditingController pendidikanSMPController = TextEditingController();
|
||||
TextEditingController pendidikanSMAController = TextEditingController();
|
||||
TextEditingController kemampuanController = TextEditingController();
|
||||
TextEditingController hobiController = TextEditingController();
|
||||
TextEditingController jkController = TextEditingController();
|
||||
|
||||
Future<void> init(int idSiswa) async {
|
||||
log.i('idSiswa: $idSiswa');
|
||||
getData(idSiswa);
|
||||
prefs.then((SharedPreferences prefs) {
|
||||
role = prefs.getString('role');
|
||||
});
|
||||
}
|
||||
|
||||
getData(int idSiswa) async {
|
||||
// log.i('idSiswa: $idSiswa');
|
||||
setBusy(true);
|
||||
easyLoading.showLoading();
|
||||
try {
|
||||
var response = await _httpService.get('siswa_detail?id=$idSiswa');
|
||||
var datanya = response.data['data'];
|
||||
siswaModel = SiswaModel.fromJson(datanya);
|
||||
notifyListeners();
|
||||
log.i(siswaModel!.imgUrl);
|
||||
namaController.text = siswaModel!.nama!;
|
||||
tanggalLahirController.text = siswaModel!.tanggalLahir!;
|
||||
tempatLahirController.text = siswaModel!.tempatLahir!;
|
||||
alamatController.text = siswaModel!.alamat!;
|
||||
noTelponController.text = siswaModel!.noTelpon!;
|
||||
agamaController.text = siswaModel!.agama!;
|
||||
kewarganegaraanController.text = siswaModel!.kewarganegaraan!;
|
||||
pendidikanSDController.text = siswaModel!.pendidikanSd!;
|
||||
pendidikanSMPController.text = siswaModel!.pendidikanSmp!;
|
||||
pendidikanSMAController.text = siswaModel!.pendidikanSma!;
|
||||
kemampuanController.text = siswaModel!.kemampuan!;
|
||||
hobiController.text = siswaModel!.hobi!;
|
||||
jkController.text = siswaModel!.jenisKelamin!;
|
||||
} catch (e) {
|
||||
log.e(e);
|
||||
} finally {
|
||||
setBusy(false);
|
||||
easyLoading.dismissLoading();
|
||||
}
|
||||
}
|
||||
|
||||
void deleteData() async {
|
||||
setBusy(true);
|
||||
easyLoading.showLoading();
|
||||
try {
|
||||
var response = await _httpService.postWithFormData(
|
||||
'siswa_delete',
|
||||
FormData.fromMap(
|
||||
{
|
||||
'id': siswaModel!.idSiswa,
|
||||
},
|
||||
),
|
||||
);
|
||||
log.i(response.data);
|
||||
|
||||
snackbarService.showSnackbar(
|
||||
message: 'Data berhasil dihapus',
|
||||
title: 'Berhasil',
|
||||
duration: const Duration(seconds: 2),
|
||||
);
|
||||
// navigationService.back();
|
||||
} catch (e) {
|
||||
snackbarService.showSnackbar(
|
||||
message: 'Data gagal dihapus',
|
||||
title: 'Gagal',
|
||||
duration: const Duration(seconds: 2),
|
||||
);
|
||||
log.e(e);
|
||||
} finally {
|
||||
setBusy(false);
|
||||
easyLoading.dismissLoading();
|
||||
}
|
||||
}
|
||||
|
||||
editData() async {
|
||||
var res = await dialogService.showCustomDialog(
|
||||
variant: DialogType.editDialogSiswaView,
|
||||
data: siswaModel,
|
||||
);
|
||||
|
||||
if (res?.confirmed != true) {
|
||||
init(int.parse(siswaModel!.idSiswa!));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,284 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:stacked/stacked.dart';
|
||||
import 'package:stacked_services/stacked_services.dart';
|
||||
|
||||
import '../../../../app/themes/app_colors.dart';
|
||||
import '../../../../app/themes/app_text.dart';
|
||||
import './filter_dialog_view_model.dart';
|
||||
|
||||
class FilterDialogView extends StatelessWidget {
|
||||
final DialogRequest? request;
|
||||
final Function(DialogResponse)? completer;
|
||||
|
||||
const FilterDialogView({
|
||||
Key? key,
|
||||
this.request,
|
||||
this.completer,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ViewModelBuilder<FilterDialogViewModel>.reactive(
|
||||
viewModelBuilder: () => FilterDialogViewModel(),
|
||||
onViewModelReady: (FilterDialogViewModel model) async {
|
||||
await model.init();
|
||||
},
|
||||
builder: (
|
||||
BuildContext context,
|
||||
FilterDialogViewModel model,
|
||||
Widget? child,
|
||||
) {
|
||||
return Dialog(
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
),
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
),
|
||||
padding: const EdgeInsets.all(10),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
"FILTER LAPORAN",
|
||||
style: boldTextStyle.copyWith(
|
||||
fontSize: 16,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
Align(
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Text(
|
||||
"Jenis Dana Sosial",
|
||||
style: regularTextStyle.copyWith(color: mainColor),
|
||||
textAlign: TextAlign.left,
|
||||
),
|
||||
),
|
||||
Container(
|
||||
width: double.infinity,
|
||||
height: 60,
|
||||
padding: const EdgeInsets.all(15),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(25),
|
||||
border: Border.all(
|
||||
color: mainColor,
|
||||
),
|
||||
),
|
||||
child: DropdownButtonHideUnderline(
|
||||
child: DropdownButton<String>(
|
||||
value: model.jenisDonasi,
|
||||
onChanged: (String? newValue) {
|
||||
// model.setSelectedjenisDonasi(newValue!);
|
||||
model.log.i(newValue);
|
||||
model.jenisDonasi = newValue!;
|
||||
model.notifyListeners();
|
||||
},
|
||||
items: model.jenisDonasiList.map((String value) {
|
||||
return DropdownMenuItem<String>(
|
||||
value: value,
|
||||
child: Text(
|
||||
value,
|
||||
style: regularTextStyle.copyWith(
|
||||
fontSize: 16,
|
||||
),
|
||||
),
|
||||
);
|
||||
}).toList(),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
Align(
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Text(
|
||||
"Filter Bulan",
|
||||
style: regularTextStyle.copyWith(color: mainColor),
|
||||
textAlign: TextAlign.left,
|
||||
),
|
||||
),
|
||||
Container(
|
||||
width: double.infinity,
|
||||
height: 60,
|
||||
padding: const EdgeInsets.all(15),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(25),
|
||||
border: Border.all(
|
||||
color: mainColor,
|
||||
),
|
||||
),
|
||||
child: DropdownButtonHideUnderline(
|
||||
child: DropdownButton<String>(
|
||||
value: model.bulan,
|
||||
onChanged: (String? newValue) {
|
||||
// model.setSelectedbulan(newValue!);
|
||||
model.log.i(newValue);
|
||||
model.bulan = newValue!;
|
||||
model.notifyListeners();
|
||||
},
|
||||
items: model.bulanList.map((String value) {
|
||||
return DropdownMenuItem<String>(
|
||||
value: value,
|
||||
child: Text(
|
||||
value,
|
||||
style: regularTextStyle.copyWith(
|
||||
fontSize: 16,
|
||||
),
|
||||
),
|
||||
);
|
||||
}).toList(),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
Align(
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Text(
|
||||
"Filter Tahun",
|
||||
style: regularTextStyle.copyWith(color: mainColor),
|
||||
textAlign: TextAlign.left,
|
||||
),
|
||||
),
|
||||
Container(
|
||||
width: double.infinity,
|
||||
height: 60,
|
||||
padding: const EdgeInsets.all(15),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(25),
|
||||
border: Border.all(
|
||||
color: mainColor,
|
||||
),
|
||||
),
|
||||
child: DropdownButtonHideUnderline(
|
||||
child: DropdownButton<String>(
|
||||
value: model.tahun,
|
||||
onChanged: (String? newValue) {
|
||||
// model.setSelectedtahun(newValue!);
|
||||
model.log.i(newValue);
|
||||
model.tahun = newValue!;
|
||||
model.notifyListeners();
|
||||
},
|
||||
items: model.tahunList.map((String value) {
|
||||
return DropdownMenuItem<String>(
|
||||
value: value,
|
||||
child: Text(
|
||||
value,
|
||||
style: regularTextStyle.copyWith(
|
||||
fontSize: 16,
|
||||
),
|
||||
),
|
||||
);
|
||||
}).toList(),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
Align(
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Text(
|
||||
"Filter Status",
|
||||
style: regularTextStyle.copyWith(color: mainColor),
|
||||
textAlign: TextAlign.left,
|
||||
),
|
||||
),
|
||||
Container(
|
||||
width: double.infinity,
|
||||
height: 60,
|
||||
padding: const EdgeInsets.all(15),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(25),
|
||||
border: Border.all(
|
||||
color: mainColor,
|
||||
),
|
||||
),
|
||||
child: DropdownButtonHideUnderline(
|
||||
child: DropdownButton<String>(
|
||||
value: model.status,
|
||||
onChanged: (String? newValue) {
|
||||
// model.setSelectedstatus(newValue!);
|
||||
model.log.i(newValue);
|
||||
model.status = newValue!;
|
||||
model.notifyListeners();
|
||||
},
|
||||
items: model.statusList.map((String value) {
|
||||
return DropdownMenuItem<String>(
|
||||
value: value,
|
||||
child: Text(
|
||||
value,
|
||||
style: regularTextStyle.copyWith(
|
||||
fontSize: 16,
|
||||
),
|
||||
),
|
||||
);
|
||||
}).toList(),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 15),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
children: [
|
||||
Expanded(
|
||||
child: TextButton(
|
||||
onPressed: () {
|
||||
// model.filter();
|
||||
// model.filter();
|
||||
completer!(
|
||||
DialogResponse(
|
||||
confirmed: true,
|
||||
data: {
|
||||
'jenisDonasi': model.jenisDonasi,
|
||||
'bulan': model.bulan,
|
||||
'tahun': model.tahun,
|
||||
'status': model.status,
|
||||
},
|
||||
),
|
||||
);
|
||||
},
|
||||
style: TextButton.styleFrom(
|
||||
backgroundColor: mainColor,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(25),
|
||||
),
|
||||
),
|
||||
child: Text(
|
||||
"Filter",
|
||||
style: boldTextStyle.copyWith(
|
||||
fontSize: 16,
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 10),
|
||||
Expanded(
|
||||
child: TextButton(
|
||||
onPressed: () {
|
||||
completer!(DialogResponse(confirmed: false));
|
||||
},
|
||||
style: TextButton.styleFrom(
|
||||
backgroundColor: mainGrey,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(25),
|
||||
),
|
||||
),
|
||||
child: Text(
|
||||
"Close",
|
||||
style: boldTextStyle.copyWith(
|
||||
fontSize: 16,
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
import '../../../../app/app.logger.dart';
|
||||
import '../../../../app/core/custom_base_view_model.dart';
|
||||
|
||||
class FilterDialogViewModel extends CustomBaseViewModel {
|
||||
final log = getLogger('FilterDialogViewModel');
|
||||
|
||||
String jenisDonasi = 'Semua';
|
||||
List<String> jenisDonasiList = ['Semua', 'Uang', 'Barang'];
|
||||
|
||||
String bulan = 'Semua';
|
||||
List<String> bulanList = [
|
||||
'Semua',
|
||||
'Januari',
|
||||
'Februari',
|
||||
'Maret',
|
||||
'April',
|
||||
'Mei',
|
||||
'Juni',
|
||||
'Juli',
|
||||
'Agustus',
|
||||
'September',
|
||||
'Oktober',
|
||||
'November',
|
||||
'Desember'
|
||||
];
|
||||
|
||||
String tahun = 'Semua';
|
||||
List<String> tahunList = [
|
||||
'Semua',
|
||||
'2024',
|
||||
'2023',
|
||||
'2022',
|
||||
];
|
||||
|
||||
String status = 'Semua';
|
||||
List<String> statusList = [
|
||||
'Semua',
|
||||
'Belum Dikonfirmasi',
|
||||
'Sudah Dikonfirmasi',
|
||||
];
|
||||
|
||||
Future<void> init() async {}
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:stacked/stacked.dart';
|
||||
|
||||
import '../../../../app/themes/app_text.dart';
|
||||
import './profil_view_model.dart';
|
||||
|
||||
class ProfilView extends StatelessWidget {
|
||||
|
@ -18,10 +19,57 @@ class ProfilView extends StatelessWidget {
|
|||
ProfilViewModel model,
|
||||
Widget? child,
|
||||
) {
|
||||
return const Scaffold(
|
||||
body: Center(
|
||||
child: Text(
|
||||
'ProfilView',
|
||||
return Scaffold(
|
||||
body: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 15),
|
||||
child: Column(
|
||||
children: [
|
||||
const Center(
|
||||
child: Image(
|
||||
image: AssetImage("assets/logo.png"),
|
||||
width: 200,
|
||||
height: 200,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
Text(
|
||||
"PANTI ASUHAN ABADI AISYIYAH",
|
||||
style: boldTextStyle.copyWith(
|
||||
fontSize: 20,
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: const [
|
||||
Icon(Icons.phone),
|
||||
SizedBox(width: 15),
|
||||
Expanded(
|
||||
child: Text(
|
||||
"085 298 962 023",
|
||||
textAlign: TextAlign.justify,
|
||||
style: regularTextStyle,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: const [
|
||||
Icon(Icons.location_on),
|
||||
SizedBox(width: 15),
|
||||
Expanded(
|
||||
child: Text(
|
||||
"Jln Panti Asuhan No. 3 Ujung Lare, Kec. Soreang, Kota Parepare, Sulawesi Selatan 91133",
|
||||
textAlign: TextAlign.justify,
|
||||
style: regularTextStyle,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:stacked/stacked.dart';
|
||||
|
||||
import './sejarah_view_model.dart';
|
||||
|
||||
class SejarahView extends StatelessWidget {
|
||||
const SejarahView({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ViewModelBuilder<SejarahViewModel>.nonReactive(
|
||||
viewModelBuilder: () => SejarahViewModel(),
|
||||
onViewModelReady: (SejarahViewModel model) async {
|
||||
await model.init();
|
||||
},
|
||||
builder: (
|
||||
BuildContext context,
|
||||
SejarahViewModel model,
|
||||
Widget? child,
|
||||
) {
|
||||
return Scaffold(
|
||||
body: Padding(
|
||||
padding: const EdgeInsets.all(20),
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
children: [
|
||||
const Center(
|
||||
child: Image(
|
||||
image: AssetImage("assets/logo.png"),
|
||||
width: 150,
|
||||
height: 150,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
Text(
|
||||
'${model.isi1}\n\n${model.isi2}',
|
||||
style: const TextStyle(fontSize: 18),
|
||||
textAlign: TextAlign.justify,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
import 'package:panti_asuhan/app/core/custom_base_view_model.dart';
|
||||
|
||||
class SejarahViewModel extends CustomBaseViewModel {
|
||||
String isi1 =
|
||||
"Panti Asuhan Abadi Aisiyah Kota Parepare dibangun secara bertahap yang peletakan batu pertamanya pada tahun 1960, dan mulai ditempati pada tahun 1962, sehingga tahun berdirinya Panti Asuhan Abadi Aisyiyah Kota Parepare pada Tahun 1963";
|
||||
|
||||
String isi2 =
|
||||
"Pada perkembangannya dibangun bangunan yang ada pada sebelah kiri bangunan p[ertama, kemudia dibangun lagi Mushollah, dan pembangunannya sepenuhnya bantuan prisden Soeharto pada waktu itu. Pada perkembangan berikutnya karena jalan masukke Panti Asuhan Masih berupa pematang sawah, maka oleh Hj. Syamsiah Jabbar sebagai pengelolah pertama meminta Pemerintah untuk meninjau jalan tersebut dan pada tahun 1964-1965 oleh Pemerintah dibangun jalanan beraspal";
|
||||
|
||||
Future<void> init() async {}
|
||||
}
|
|
@ -0,0 +1,253 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:panti_asuhan/app/themes/app_text.dart';
|
||||
import 'package:panti_asuhan/ui/widgets/my_button.dart';
|
||||
import 'package:panti_asuhan/ui/widgets/my_textformfield.dart';
|
||||
import 'package:stacked/stacked.dart';
|
||||
import 'package:stacked_services/stacked_services.dart';
|
||||
|
||||
import './edit_strukrur_organisasi_dialog_view_model.dart';
|
||||
|
||||
class EditStrukrurOrganisasiDialogView extends StatelessWidget {
|
||||
final DialogRequest? request;
|
||||
final Function(DialogResponse)? completer;
|
||||
|
||||
const EditStrukrurOrganisasiDialogView({
|
||||
Key? key,
|
||||
this.request,
|
||||
this.completer,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ViewModelBuilder<EditStrukrurOrganisasiDialogViewModel>.reactive(
|
||||
viewModelBuilder: () => EditStrukrurOrganisasiDialogViewModel(),
|
||||
onViewModelReady: (EditStrukrurOrganisasiDialogViewModel model) async {
|
||||
await model.init(
|
||||
request!.data,
|
||||
);
|
||||
},
|
||||
builder: (
|
||||
BuildContext context,
|
||||
EditStrukrurOrganisasiDialogViewModel model,
|
||||
Widget? child,
|
||||
) {
|
||||
return Dialog(
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
),
|
||||
child: Container(
|
||||
padding: const EdgeInsets.all(20),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
),
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Stack(
|
||||
children: [
|
||||
SingleChildScrollView(
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: model.child,
|
||||
),
|
||||
),
|
||||
// top right rounded add button
|
||||
request?.data['tambahan'] == false
|
||||
? const SizedBox()
|
||||
: Positioned(
|
||||
top: 0,
|
||||
right: 0,
|
||||
child: GestureDetector(
|
||||
onTap: () {
|
||||
model.addWidget();
|
||||
// model.check();
|
||||
},
|
||||
child: Container(
|
||||
padding: const EdgeInsets.all(5),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.green,
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
),
|
||||
child: const Icon(
|
||||
Icons.add,
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(
|
||||
height: 10,
|
||||
),
|
||||
SizedBox(
|
||||
width: 150,
|
||||
child: MyButton(
|
||||
text: 'Simpan',
|
||||
onPressed: () {
|
||||
// model.check();
|
||||
model.uploadJabatan(completer!);
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class TheWidget extends ViewModelWidget<EditStrukrurOrganisasiDialogViewModel> {
|
||||
final TextEditingController controller;
|
||||
final int index;
|
||||
@override
|
||||
// ignore: overridden_fields
|
||||
final Key key;
|
||||
|
||||
const TheWidget({
|
||||
required this.key,
|
||||
required this.controller,
|
||||
required this.index,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(
|
||||
BuildContext context, EditStrukrurOrganisasiDialogViewModel viewModel) {
|
||||
return Stack(
|
||||
children: [
|
||||
Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
// ignore: prefer_const_literals_to_create_immutables
|
||||
children: [
|
||||
Center(
|
||||
child: FotoWidget(
|
||||
index: index,
|
||||
)),
|
||||
const SizedBox(height: 10),
|
||||
const Text(
|
||||
' Nama',
|
||||
style: regularTextStyle,
|
||||
),
|
||||
MyTextFormField(
|
||||
controller: controller,
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
// straight line divider
|
||||
const Divider(
|
||||
color: Colors.grey,
|
||||
height: 20,
|
||||
thickness: 1,
|
||||
indent: 0,
|
||||
endIndent: 0,
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
],
|
||||
),
|
||||
// top right rounded add button
|
||||
index == 1
|
||||
? const SizedBox()
|
||||
: Positioned(
|
||||
top: 0,
|
||||
right: 0,
|
||||
child: GestureDetector(
|
||||
onTap: () {
|
||||
viewModel.removeWidget(index, key);
|
||||
},
|
||||
child: Container(
|
||||
padding: const EdgeInsets.all(5),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.red,
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
),
|
||||
child: const Icon(
|
||||
Icons.remove,
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class FotoWidget
|
||||
extends ViewModelWidget<EditStrukrurOrganisasiDialogViewModel> {
|
||||
final int index;
|
||||
|
||||
const FotoWidget({
|
||||
Key? key,
|
||||
required this.index,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(
|
||||
BuildContext context, EditStrukrurOrganisasiDialogViewModel viewModel) {
|
||||
return Container(
|
||||
width: 100,
|
||||
height: 100,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(150),
|
||||
// color: Colors.grey,
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.grey.withOpacity(0.5),
|
||||
spreadRadius: 2,
|
||||
blurRadius: 5,
|
||||
),
|
||||
],
|
||||
),
|
||||
child: Stack(
|
||||
children: [
|
||||
Center(
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
child: viewModel.imageBytes['image$index'] == null
|
||||
? const Icon(
|
||||
Icons.person,
|
||||
size: 90,
|
||||
)
|
||||
: ClipRRect(
|
||||
borderRadius: BorderRadius.circular(50),
|
||||
child: Image.memory(
|
||||
viewModel.imageBytes['image$index']!,
|
||||
width: 100,
|
||||
height: 100,
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
bottom: 0,
|
||||
right: 0,
|
||||
child: GestureDetector(
|
||||
onTap: () {
|
||||
viewModel.addImage(index);
|
||||
},
|
||||
child: Container(
|
||||
width: 30,
|
||||
height: 30,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(150),
|
||||
color: Colors.grey,
|
||||
),
|
||||
child: const Icon(
|
||||
Icons.edit,
|
||||
size: 20,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,178 @@
|
|||
import 'dart:typed_data';
|
||||
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:http_parser/http_parser.dart';
|
||||
import 'package:image_picker/image_picker.dart';
|
||||
import 'package:stacked_services/stacked_services.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';
|
||||
import 'edit_strukrur_organisasi_dialog_view.dart';
|
||||
|
||||
class EditStrukrurOrganisasiDialogViewModel extends CustomBaseViewModel {
|
||||
final log = getLogger('EditStrukrurOrganisasiDialogViewModel');
|
||||
final easyloading = locator<MyEasyLoading>();
|
||||
final _httpService = locator<MyHttpServices>();
|
||||
|
||||
List<Widget> child = [];
|
||||
Map<String, TextEditingController> controllers = {};
|
||||
int controllerIndex = 1;
|
||||
|
||||
Map<String, Key> keys = {};
|
||||
|
||||
// image picker
|
||||
Map<String, String> imagePaths = {};
|
||||
ImagePicker picker = ImagePicker();
|
||||
Map<String, XFile> imageFiles = {};
|
||||
Map<String, Uint8List> imageBytes = {};
|
||||
|
||||
late String name;
|
||||
|
||||
Future<void> init(data) async {
|
||||
name = data['jabatan'];
|
||||
log.i(data);
|
||||
// create controller
|
||||
createController('$name$controllerIndex');
|
||||
keys['$name$controllerIndex'] = UniqueKey();
|
||||
|
||||
// add theWidget to child
|
||||
child.add(TheWidget(
|
||||
controller: controllers['$name$controllerIndex']!,
|
||||
index: controllerIndex,
|
||||
key: keys['$name$controllerIndex']!,
|
||||
));
|
||||
}
|
||||
|
||||
void createController(String key) {
|
||||
controllers[key] = TextEditingController();
|
||||
}
|
||||
|
||||
void addWidget() {
|
||||
controllerIndex++;
|
||||
createController('$name$controllerIndex');
|
||||
keys['$name$controllerIndex'] = UniqueKey();
|
||||
child.add(TheWidget(
|
||||
controller: controllers['$name$controllerIndex']!,
|
||||
index: controllerIndex,
|
||||
key: keys['$name$controllerIndex']!,
|
||||
));
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
void disposeSingleController(String key) {
|
||||
controllers[key]!.dispose();
|
||||
controllers.remove(key);
|
||||
}
|
||||
|
||||
check() {
|
||||
log.i(controllers);
|
||||
}
|
||||
|
||||
/////////// utk gambar //////////////
|
||||
|
||||
void addImage(int index) async {
|
||||
try {
|
||||
final XFile? image = await picker.pickImage(source: ImageSource.gallery);
|
||||
if (image != null) {
|
||||
imageFiles['image$index'] = image;
|
||||
imagePaths['image$index'] = image.path;
|
||||
imageBytes['image$index'] = await image.readAsBytes();
|
||||
|
||||
log.i('image path: ${imagePaths['image$index']}');
|
||||
notifyListeners();
|
||||
}
|
||||
} catch (e) {
|
||||
log.e(e);
|
||||
}
|
||||
}
|
||||
|
||||
uploadJabatan(Function(DialogResponse p1) completer) async {
|
||||
// check if the controller is empty
|
||||
for (var i = 1; i <= controllers.length; i++) {
|
||||
String key = controllers.keys.elementAt(i - 1);
|
||||
if (controllers[key]!.text.isEmpty) {
|
||||
snackbarService.showSnackbar(
|
||||
message: 'Nama tidak boleh kosong',
|
||||
title: 'Error',
|
||||
duration: const Duration(seconds: 2),
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// check if the image is empty
|
||||
for (var i = 1; i <= controllers.length; i++) {
|
||||
// String key = controllers.keys.elementAt(i - 1);
|
||||
if (!imagePaths.containsKey('image$i')) {
|
||||
snackbarService.showSnackbar(
|
||||
message: 'Gambar tidak boleh kosong',
|
||||
title: 'Error',
|
||||
duration: const Duration(seconds: 2),
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
setBusy(true);
|
||||
easyloading.customLoading('Edit Detail Jabatan $name');
|
||||
Map<String, dynamic> array = {
|
||||
'jabatan': name,
|
||||
'jumlah': controllers.length.toString(),
|
||||
};
|
||||
|
||||
// log.i(imagePaths.values);
|
||||
|
||||
// rearrange the data
|
||||
for (var i = 1; i <= controllers.length; i++) {
|
||||
String key = controllers.keys.elementAt(i - 1);
|
||||
array['nama$i'] = controllers[key]!.text;
|
||||
// array['nama$i'] = controllers['$name$i']!.text;
|
||||
array['image$i'] = await MultipartFile.fromFile(
|
||||
imagePaths.values.elementAt(i - 1),
|
||||
filename: imageFiles.values.elementAt(i - 1).name,
|
||||
contentType: MediaType.parse('image/jpeg'),
|
||||
);
|
||||
}
|
||||
FormData formData = FormData.fromMap(array);
|
||||
// log.i(array);
|
||||
try {
|
||||
// // // log.i(formData.fields);
|
||||
await _httpService.postWithFormData('edit_jabatan', formData);
|
||||
|
||||
// log.i(response.data);
|
||||
completer(
|
||||
DialogResponse(confirmed: true),
|
||||
);
|
||||
} catch (e) {
|
||||
log.e(e);
|
||||
completer(
|
||||
DialogResponse(confirmed: false),
|
||||
);
|
||||
} finally {
|
||||
easyloading.dismissLoading();
|
||||
setBusy(false);
|
||||
}
|
||||
}
|
||||
|
||||
void removeWidget(int index, Key containerKey) {
|
||||
log.i('remove widget $index');
|
||||
// remove the widget that has key
|
||||
child.removeWhere((element) => element.key == containerKey);
|
||||
|
||||
// remove the controller
|
||||
disposeSingleController('$name$index');
|
||||
// // remove the image
|
||||
imageFiles.remove('image$index');
|
||||
imagePaths.remove('image$index');
|
||||
imageBytes.remove('image$index');
|
||||
|
||||
log.i(controllers);
|
||||
log.i(imagePaths);
|
||||
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,335 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_dotenv/flutter_dotenv.dart';
|
||||
import 'package:stacked/stacked.dart';
|
||||
|
||||
import './struktur_organisasi_view_model.dart';
|
||||
|
||||
class StrukturOrganisasiView extends StatelessWidget {
|
||||
const StrukturOrganisasiView({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ViewModelBuilder<StrukturOrganisasiViewModel>.reactive(
|
||||
viewModelBuilder: () => StrukturOrganisasiViewModel(),
|
||||
onViewModelReady: (StrukturOrganisasiViewModel model) async {
|
||||
await model.init();
|
||||
},
|
||||
builder: (
|
||||
BuildContext context,
|
||||
StrukturOrganisasiViewModel model,
|
||||
Widget? child,
|
||||
) {
|
||||
return Scaffold(
|
||||
body: Padding(
|
||||
padding: const EdgeInsets.all(20),
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
children: [
|
||||
const Center(
|
||||
child: Image(
|
||||
image: AssetImage("assets/logo.png"),
|
||||
width: 150,
|
||||
height: 150,
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 20,
|
||||
),
|
||||
FirstWidget(
|
||||
title: "Ketua",
|
||||
data: model.dataKetua,
|
||||
),
|
||||
const SizedBox(
|
||||
height: 20,
|
||||
),
|
||||
FirstWidget(
|
||||
title: 'Sekretaris',
|
||||
data: model.dataSekretaris,
|
||||
),
|
||||
const SizedBox(
|
||||
height: 20,
|
||||
),
|
||||
FirstWidget(
|
||||
title: 'Bendahara',
|
||||
data: model.dataBendahara,
|
||||
),
|
||||
const SizedBox(
|
||||
height: 20,
|
||||
),
|
||||
FirstWidget(
|
||||
title: 'Wakil Bendahara',
|
||||
data: model.dataWakilBendahara,
|
||||
),
|
||||
const SizedBox(
|
||||
height: 20,
|
||||
),
|
||||
SecondWidget(
|
||||
title: 'Seksi Pengasuh',
|
||||
data: model.dataPengasuh,
|
||||
length: model.dataPengasuhLength,
|
||||
),
|
||||
const SizedBox(
|
||||
height: 20,
|
||||
),
|
||||
SecondWidget(
|
||||
title: 'Seksi Ibadah',
|
||||
data: model.dataIbadah,
|
||||
length: model.dataIbadahLength,
|
||||
),
|
||||
const SizedBox(
|
||||
height: 20,
|
||||
),
|
||||
SecondWidget(
|
||||
title: 'Seksi Pendidikan',
|
||||
data: model.dataPendidikan,
|
||||
length: model.dataPendidikanLength,
|
||||
),
|
||||
const SizedBox(
|
||||
height: 20,
|
||||
),
|
||||
SecondWidget(
|
||||
title: 'Seksi Kesehatan',
|
||||
data: model.dataKesehatan,
|
||||
length: model.dataKesehatanLength,
|
||||
),
|
||||
const SizedBox(
|
||||
height: 20,
|
||||
),
|
||||
SecondWidget(
|
||||
title: 'Seksi Kebersihan',
|
||||
data: model.dataKebersihan,
|
||||
length: model.dataKebersihanLength,
|
||||
),
|
||||
const SizedBox(
|
||||
height: 20,
|
||||
),
|
||||
SecondWidget(
|
||||
title: 'Seksi Keterampilan',
|
||||
data: model.dataKeterampilan,
|
||||
length: model.dataKeterampilanLength,
|
||||
),
|
||||
const SizedBox(
|
||||
height: 20,
|
||||
),
|
||||
SecondWidget(
|
||||
title: 'Sarana dan Prasarana',
|
||||
data: model.dataSaranaDanPrasarana,
|
||||
length: model.dataSaranaDanPrasaranaLength,
|
||||
),
|
||||
const SizedBox(
|
||||
height: 20,
|
||||
),
|
||||
SecondWidget(
|
||||
title: 'Seksi Konsumsi',
|
||||
data: model.dataKonsumsi,
|
||||
length: model.dataKonsumsiLength,
|
||||
),
|
||||
const SizedBox(
|
||||
height: 20,
|
||||
),
|
||||
SecondWidget(
|
||||
title: 'Seksi Keamanan',
|
||||
data: model.dataKeamanan,
|
||||
length: model.dataKeamananLength,
|
||||
),
|
||||
const SizedBox(
|
||||
height: 20,
|
||||
),
|
||||
SecondWidget(
|
||||
title: 'Seksi Gedung',
|
||||
data: model.dataGedung,
|
||||
length: model.dataGedungLength,
|
||||
),
|
||||
const SizedBox(
|
||||
height: 20,
|
||||
),
|
||||
SecondWidget(
|
||||
title: 'Seksi Wisma',
|
||||
data: model.dataWisma,
|
||||
length: model.dataWismaLength,
|
||||
),
|
||||
const SizedBox(
|
||||
height: 20,
|
||||
),
|
||||
SecondWidget(
|
||||
title: 'Kelompok Putra',
|
||||
data: model.dataKelompokPutra,
|
||||
length: model.dataKelompokPutraLength,
|
||||
),
|
||||
const SizedBox(
|
||||
height: 20,
|
||||
),
|
||||
SecondWidget(
|
||||
title: 'Kelompok Putri',
|
||||
data: model.dataKelompokPutri,
|
||||
length: model.dataKelompokPutriLength,
|
||||
),
|
||||
const SizedBox(
|
||||
height: 20,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class SecondWidget extends ViewModelWidget<StrukturOrganisasiViewModel> {
|
||||
final String title;
|
||||
final Map<String, dynamic> data;
|
||||
final int length;
|
||||
|
||||
const SecondWidget({
|
||||
super.key,
|
||||
required this.title,
|
||||
required this.data,
|
||||
required this.length,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, StrukturOrganisasiViewModel viewModel) {
|
||||
return Card(
|
||||
elevation: 4,
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
Text(
|
||||
title,
|
||||
style: const TextStyle(
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
width: 10,
|
||||
),
|
||||
viewModel.role == 'admin'
|
||||
? IconButton(
|
||||
onPressed: () {
|
||||
viewModel.editData(title, true);
|
||||
},
|
||||
icon: const Icon(Icons.edit),
|
||||
)
|
||||
: const SizedBox(),
|
||||
],
|
||||
),
|
||||
for (var i = 0; i < length; i++)
|
||||
Column(
|
||||
children: [
|
||||
Center(
|
||||
child: data.isEmpty
|
||||
? null
|
||||
: ClipRRect(
|
||||
borderRadius: BorderRadius.circular(50),
|
||||
child: Image.network(
|
||||
'${dotenv.env['url']}${data['img_url$i']}',
|
||||
width: 100,
|
||||
height: 100,
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 2,
|
||||
),
|
||||
Text(
|
||||
data['nama$i'] ?? '...',
|
||||
style: const TextStyle(
|
||||
fontSize: 20,
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 5,
|
||||
),
|
||||
// create a line
|
||||
const Divider(
|
||||
color: Colors.black,
|
||||
height: 20,
|
||||
thickness: 1,
|
||||
indent: 20,
|
||||
endIndent: 20,
|
||||
),
|
||||
const SizedBox(height: 5),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class FirstWidget extends ViewModelWidget<StrukturOrganisasiViewModel> {
|
||||
final String title;
|
||||
final Map<String, dynamic> data;
|
||||
|
||||
const FirstWidget({
|
||||
super.key,
|
||||
required this.title,
|
||||
required this.data,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, StrukturOrganisasiViewModel viewModel) {
|
||||
return Card(
|
||||
elevation: 4,
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
Text(
|
||||
title,
|
||||
style: const TextStyle(
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
width: 10,
|
||||
),
|
||||
viewModel.role == 'admin'
|
||||
? IconButton(
|
||||
onPressed: () {
|
||||
viewModel.editData(title, false);
|
||||
},
|
||||
icon: const Icon(Icons.edit),
|
||||
)
|
||||
: const SizedBox(),
|
||||
],
|
||||
),
|
||||
Center(
|
||||
child: data.isEmpty
|
||||
? null
|
||||
: ClipRRect(
|
||||
borderRadius: BorderRadius.circular(50),
|
||||
child: Image.network(
|
||||
'${dotenv.env['url']}${data['img_url']}',
|
||||
width: 100,
|
||||
height: 100,
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 2,
|
||||
),
|
||||
Text(
|
||||
data['nama'] ?? '...',
|
||||
style: const TextStyle(
|
||||
fontSize: 20,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,178 @@
|
|||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
|
||||
import '../../../../app/app.dialogs.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 StrukturOrganisasiViewModel extends CustomBaseViewModel {
|
||||
final log = getLogger('StrukturOrganisasiViewModel');
|
||||
final _httpService = locator<MyHttpServices>();
|
||||
final easyLoading = locator<MyEasyLoading>();
|
||||
String? role;
|
||||
|
||||
Map<String, dynamic> dataKetua = {};
|
||||
Map<String, dynamic> dataSekretaris = {};
|
||||
Map<String, dynamic> dataBendahara = {};
|
||||
Map<String, dynamic> dataWakilBendahara = {};
|
||||
|
||||
Map<String, dynamic> dataPengasuh = {};
|
||||
int dataPengasuhLength = 0;
|
||||
|
||||
Map<String, dynamic> dataIbadah = {};
|
||||
int dataIbadahLength = 0;
|
||||
|
||||
Map<String, dynamic> dataPendidikan = {};
|
||||
int dataPendidikanLength = 0;
|
||||
|
||||
Map<String, dynamic> dataKebersihan = {};
|
||||
int dataKebersihanLength = 0;
|
||||
|
||||
Map<String, dynamic> dataKesehatan = {};
|
||||
int dataKesehatanLength = 0;
|
||||
|
||||
Map<String, dynamic> dataKeterampilan = {};
|
||||
int dataKeterampilanLength = 0;
|
||||
|
||||
Map<String, dynamic> dataSaranaDanPrasarana = {};
|
||||
int dataSaranaDanPrasaranaLength = 0;
|
||||
|
||||
Map<String, dynamic> dataKonsumsi = {};
|
||||
int dataKonsumsiLength = 0;
|
||||
|
||||
Map<String, dynamic> dataKeamanan = {};
|
||||
int dataKeamananLength = 0;
|
||||
|
||||
Map<String, dynamic> dataGedung = {};
|
||||
int dataGedungLength = 0;
|
||||
|
||||
Map<String, dynamic> dataWisma = {};
|
||||
int dataWismaLength = 0;
|
||||
|
||||
Map<String, dynamic> dataKelompokPutra = {};
|
||||
int dataKelompokPutraLength = 0;
|
||||
|
||||
Map<String, dynamic> dataKelompokPutri = {};
|
||||
int dataKelompokPutriLength = 0;
|
||||
|
||||
Future<void> init() async {
|
||||
prefs.then((SharedPreferences prefs) {
|
||||
role = prefs.getString('role');
|
||||
});
|
||||
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);
|
||||
getData('Seksi Kebersihan', true, dataKebersihanLength);
|
||||
getData('Seksi Kesehatan', true, dataKesehatanLength);
|
||||
getData('Seksi Keterampilan', true, dataKeterampilanLength);
|
||||
getData('Sarana dan Prasarana', true, dataSaranaDanPrasaranaLength);
|
||||
getData('Seksi Konsumsi', true, dataKonsumsiLength);
|
||||
getData('Seksi Keamanan', true, dataKeamananLength);
|
||||
getData('Seksi Gedung', true, dataGedungLength);
|
||||
getData('Seksi Wisma', true, dataWismaLength);
|
||||
getData('Kelompok Putra', true, dataKelompokPutraLength);
|
||||
getData('Kelompok Putri', true, dataKelompokPutriLength);
|
||||
}
|
||||
|
||||
getData(String jabatan, bool stat, int? length) async {
|
||||
easyLoading.customLoading('Loading Data');
|
||||
setBusy(true);
|
||||
|
||||
try {
|
||||
var response = await _httpService.get('jabatan?jabatan=$jabatan');
|
||||
// log.i(response.data);
|
||||
if (response.data['data'].length == 0) return;
|
||||
Map<String, dynamic> data = {};
|
||||
if (!stat) {
|
||||
var datanya = response.data['data'][0];
|
||||
data['nama'] = datanya['nama'];
|
||||
data['img_url'] = datanya['img_url'];
|
||||
// log.i(data);
|
||||
// return;
|
||||
} else {
|
||||
var datanya = response.data['data'];
|
||||
length = datanya.length;
|
||||
for (var i = 0; i < datanya.length; i++) {
|
||||
data['nama$i'] = datanya[i]['nama'];
|
||||
data['img_url$i'] = datanya[i]['img_url'];
|
||||
}
|
||||
}
|
||||
|
||||
if (jabatan == 'Ketua') {
|
||||
dataKetua = data;
|
||||
} else if (jabatan == 'Sekretaris') {
|
||||
dataSekretaris = data;
|
||||
} else if (jabatan == 'Bendahara') {
|
||||
dataBendahara = data;
|
||||
} else if (jabatan == 'Wakil Bendahara') {
|
||||
dataWakilBendahara = data;
|
||||
} else if (jabatan == 'Seksi Pengasuh') {
|
||||
dataPengasuh = data;
|
||||
dataPengasuhLength = length!;
|
||||
} else if (jabatan == 'Seksi Ibadah') {
|
||||
dataIbadah = data;
|
||||
dataIbadahLength = length!;
|
||||
} else if (jabatan == 'Seksi Pendidikan') {
|
||||
dataPendidikan = data;
|
||||
dataPendidikanLength = length!;
|
||||
} else if (jabatan == 'Seksi Kebersihan') {
|
||||
dataKebersihan = data;
|
||||
dataKebersihanLength = length!;
|
||||
} else if (jabatan == 'Seksi Kesehatan') {
|
||||
dataKesehatan = data;
|
||||
dataKesehatanLength = length!;
|
||||
} else if (jabatan == 'Seksi Keterampilan') {
|
||||
dataKeterampilan = data;
|
||||
dataKeterampilanLength = length!;
|
||||
} else if (jabatan == 'Sarana dan Prasarana') {
|
||||
dataSaranaDanPrasarana = data;
|
||||
dataSaranaDanPrasaranaLength = length!;
|
||||
} else if (jabatan == 'Seksi Konsumsi') {
|
||||
dataKonsumsi = data;
|
||||
dataKonsumsiLength = length!;
|
||||
} else if (jabatan == 'Seksi Keamanan') {
|
||||
dataKeamanan = data;
|
||||
dataKeamananLength = length!;
|
||||
} else if (jabatan == 'Seksi Gedung') {
|
||||
dataGedung = data;
|
||||
dataGedungLength = length!;
|
||||
} else if (jabatan == 'Seksi Wisma') {
|
||||
dataWisma = data;
|
||||
dataWismaLength = length!;
|
||||
} else if (jabatan == 'Kelompok Putra') {
|
||||
dataKelompokPutra = data;
|
||||
dataKelompokPutraLength = length!;
|
||||
} else if (jabatan == 'Kelompok Putri') {
|
||||
dataKelompokPutri = data;
|
||||
dataKelompokPutriLength = length!;
|
||||
}
|
||||
} catch (e) {
|
||||
log.e(e);
|
||||
} finally {
|
||||
notifyListeners();
|
||||
setBusy(false);
|
||||
easyLoading.dismissLoading();
|
||||
}
|
||||
}
|
||||
|
||||
void editData(String jabatan, bool bool) {
|
||||
var res = dialogService.showCustomDialog(
|
||||
variant: DialogType.editStrukrurOrganisasiDialogView,
|
||||
data: {
|
||||
"jabatan": jabatan,
|
||||
'tambahan': bool,
|
||||
},
|
||||
);
|
||||
|
||||
res.whenComplete(() async => {
|
||||
// await Future.delayed(Duration(seconds: 1)),
|
||||
init(),
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:stacked/stacked.dart';
|
||||
|
||||
import './visi_misi_view_model.dart';
|
||||
|
||||
class VisiMisiView extends StatelessWidget {
|
||||
const VisiMisiView({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ViewModelBuilder<VisiMisiViewModel>.nonReactive(
|
||||
viewModelBuilder: () => VisiMisiViewModel(),
|
||||
onViewModelReady: (VisiMisiViewModel model) async {
|
||||
await model.init();
|
||||
},
|
||||
builder: (
|
||||
BuildContext context,
|
||||
VisiMisiViewModel model,
|
||||
Widget? child,
|
||||
) {
|
||||
return Scaffold(
|
||||
body: Padding(
|
||||
padding: const EdgeInsets.all(20),
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
children: [
|
||||
const Center(
|
||||
child: Image(
|
||||
image: AssetImage("assets/logo.png"),
|
||||
width: 150,
|
||||
height: 150,
|
||||
),
|
||||
),
|
||||
const Center(
|
||||
child: Text(
|
||||
'Visi',
|
||||
style: TextStyle(fontSize: 20),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
Text(
|
||||
model.visi,
|
||||
style: const TextStyle(fontSize: 18),
|
||||
textAlign: TextAlign.justify,
|
||||
),
|
||||
const SizedBox(height: 30),
|
||||
const Center(
|
||||
child: Text(
|
||||
'Misi',
|
||||
style: TextStyle(fontSize: 20),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
Text(
|
||||
'${model.misi1}\n\n${model.misi2}\n\n${model.misi3}\n\n${model.misi4}\n\n${model.misi5}',
|
||||
style: const TextStyle(fontSize: 18),
|
||||
textAlign: TextAlign.justify,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
import 'package:panti_asuhan/app/core/custom_base_view_model.dart';
|
||||
|
||||
class VisiMisiViewModel extends CustomBaseViewModel {
|
||||
String visi =
|
||||
"Terwujudnya anak asuhan yang berakhlak mulia sesuai dengan tujuan Pensyarikatan ";
|
||||
|
||||
String misi1 =
|
||||
"1. Mengembangkan proses pengkaderan menuju masyarakat Islam yang sebenar-benarnya";
|
||||
String misi2 =
|
||||
"2. Memberikan pembinaan Berbasis Keluarga Islami sehingga melahirkan anak asuhan yang berkarakter";
|
||||
String misi3 =
|
||||
"3. Menegmbangkan Pendidikan Inklusif secara formal dan informal.";
|
||||
String misi4 =
|
||||
"4. Meningkatkan proses belajar sehingga menjadi anak asuhan yang berkualitas dan berprilaku Islami";
|
||||
String misi5 =
|
||||
"5. Menjadikan LKSA ABADI Aisyyah sebagai tempat beramal bagu seluruh lapisan masyarakat";
|
||||
Future<void> init() async {}
|
||||
}
|
|
@ -0,0 +1,422 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:stacked/stacked.dart';
|
||||
|
||||
import '../../../app/themes/app_colors.dart';
|
||||
import '../../../app/themes/app_text.dart';
|
||||
import '../../widgets/my_textformfield.dart';
|
||||
import './detail_dana_sosial_view_model.dart';
|
||||
|
||||
class DetailDanaSosialView extends StatelessWidget {
|
||||
final int id;
|
||||
|
||||
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, isKhusus);
|
||||
},
|
||||
builder: (
|
||||
BuildContext context,
|
||||
DetailDanaSosialViewModel model,
|
||||
Widget? child,
|
||||
) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: const Text('Detail Dana Sosial',
|
||||
style: TextStyle(color: Colors.white)),
|
||||
backgroundColor: mainColor,
|
||||
iconTheme: const IconThemeData(color: Colors.white),
|
||||
),
|
||||
body: Padding(
|
||||
padding: const EdgeInsets.all(15),
|
||||
child: model.danaSosialModel == null
|
||||
? const Center(
|
||||
child: CircularProgressIndicator(),
|
||||
)
|
||||
: (model.danaSosialModel!.bentuk == 'Pemasukan'
|
||||
? const SafeArea(child: PemasukanWidget())
|
||||
: const PengeluaranWidget()),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class PengeluaranWidget extends ViewModelWidget<DetailDanaSosialViewModel> {
|
||||
const PengeluaranWidget({
|
||||
super.key,
|
||||
});
|
||||
|
||||
@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(
|
||||
"Bentuk",
|
||||
style: regularTextStyle.copyWith(color: mainColor),
|
||||
),
|
||||
),
|
||||
MyTextFormField(
|
||||
controller: viewModel.bentukController,
|
||||
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),
|
||||
),
|
||||
),
|
||||
),
|
||||
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),
|
||||
),
|
||||
),
|
||||
),
|
||||
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(
|
||||
"Dr. Andi Fitriani D, S.Ag, M.Pd",
|
||||
style: regularTextStyle.copyWith(
|
||||
color: mainColor,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
// create a horizontal line
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class PemasukanWidget extends ViewModelWidget<DetailDanaSosialViewModel> {
|
||||
const PemasukanWidget({
|
||||
super.key,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, DetailDanaSosialViewModel viewModel) {
|
||||
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),
|
||||
),
|
||||
),
|
||||
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),
|
||||
),
|
||||
),
|
||||
),
|
||||
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
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class TtdWidget extends ViewModelWidget<DetailDanaSosialViewModel> {
|
||||
const TtdWidget({
|
||||
super.key,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, DetailDanaSosialViewModel viewModel) {
|
||||
return Container(
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(color: mainColor),
|
||||
),
|
||||
child: viewModel.role == 'pimpinan' || viewModel.role == 'admin'
|
||||
? InkWell(
|
||||
onTap: () {
|
||||
viewModel.handleTtd();
|
||||
},
|
||||
child: Center(
|
||||
child: Text(
|
||||
"Tanda Tangan",
|
||||
style: regularTextStyle.copyWith(
|
||||
color: mainColor,
|
||||
fontStyle: FontStyle.italic,
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
: null,
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,127 @@
|
|||
import 'package:dio/dio.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
|
||||
import '../../../app/app.locator.dart';
|
||||
import '../../../app/app.logger.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 DetailDanaSosialViewModel extends CustomBaseViewModel {
|
||||
final log = getLogger('DetailDanaSosialViewModel');
|
||||
final _httpService = locator<MyHttpServices>();
|
||||
final easyLoading = locator<MyEasyLoading>();
|
||||
|
||||
bool isKhusus = false;
|
||||
|
||||
int? idDanaSosial;
|
||||
DanaSosialModel? danaSosialModel;
|
||||
bool jenisBool = true;
|
||||
|
||||
String? role;
|
||||
|
||||
TextEditingController namaController = TextEditingController();
|
||||
TextEditingController tanggalController = TextEditingController();
|
||||
TextEditingController jumlahController = TextEditingController();
|
||||
TextEditingController jenisController = TextEditingController();
|
||||
TextEditingController keteranganController = TextEditingController();
|
||||
|
||||
TextEditingController bentukController = TextEditingController();
|
||||
|
||||
// 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) {
|
||||
role = prefs.getString('role');
|
||||
});
|
||||
}
|
||||
|
||||
getData(int id) async {
|
||||
setBusy(true);
|
||||
easyLoading.showLoading();
|
||||
try {
|
||||
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!;
|
||||
tanggalController.text = danaSosialModel!.tanggal!;
|
||||
jumlahController.text =
|
||||
"Rp. ${OtherFunction().commaFormat(danaSosialModel!.jumlah != null ? int.parse(danaSosialModel!.jumlah!) : 0)}";
|
||||
jenisController.text = danaSosialModel!.jenisDonasi!;
|
||||
keteranganController.text = danaSosialModel!.keterangan!;
|
||||
|
||||
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 {
|
||||
jenisBool = false;
|
||||
}
|
||||
// log.i('status: ${danaSosialModel!.status}');
|
||||
setBusy(false);
|
||||
notifyListeners();
|
||||
} catch (e) {
|
||||
log.e(e);
|
||||
setBusy(false);
|
||||
} finally {
|
||||
easyLoading.dismissLoading();
|
||||
}
|
||||
}
|
||||
|
||||
void handleTtd() {
|
||||
dialogService
|
||||
.showConfirmationDialog(
|
||||
title: 'Konfirmasi',
|
||||
description: 'Apakah anda yakin ingin mengkonfirmasi tanda tangan ini?',
|
||||
cancelTitle: 'Tidak',
|
||||
confirmationTitle: 'Ya',
|
||||
)
|
||||
.then((value) async {
|
||||
if (value!.confirmed) {
|
||||
setBusy(true);
|
||||
easyLoading.showLoading();
|
||||
try {
|
||||
FormData formData = FormData.fromMap({
|
||||
'id': idDanaSosial,
|
||||
});
|
||||
String url = isKhusus ? 'dana_sosial_khusus_ttd' : 'dana_sosial_ttd';
|
||||
|
||||
var response = await _httpService.postWithFormData(url, formData);
|
||||
log.i(response.data);
|
||||
getData(idDanaSosial!);
|
||||
|
||||
setBusy(false);
|
||||
notifyListeners();
|
||||
} catch (e) {
|
||||
log.e(e);
|
||||
setBusy(false);
|
||||
dialogService.showDialog(
|
||||
title: 'Error',
|
||||
description: e.toString(),
|
||||
);
|
||||
} finally {
|
||||
easyLoading.dismissLoading();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
|
@ -1,9 +1,11 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:panti_asuhan/ui/widgets/my_button.dart';
|
||||
import 'package:panti_asuhan/ui/widgets/my_textformfield.dart';
|
||||
import 'package:stacked/stacked.dart';
|
||||
import 'package:validatorless/validatorless.dart';
|
||||
|
||||
import '../../../app/app.router.dart';
|
||||
import '../../../app/themes/app_text.dart';
|
||||
import '../../widgets/my_button.dart';
|
||||
import '../../widgets/my_textformfield.dart';
|
||||
import './login_screen_view_model.dart';
|
||||
|
||||
class LoginScreenView extends StatelessWidget {
|
||||
|
@ -24,58 +26,79 @@ class LoginScreenView extends StatelessWidget {
|
|||
return Scaffold(
|
||||
body: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 20),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
SizedBox(
|
||||
height: MediaQuery.of(context).size.height * 0.2,
|
||||
child: SingleChildScrollView(
|
||||
child: Form(
|
||||
key: model.formKey,
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
SizedBox(
|
||||
height: MediaQuery.of(context).size.height * 0.2,
|
||||
),
|
||||
// show the logo.png
|
||||
const Center(
|
||||
child: Image(
|
||||
image: AssetImage("assets/logo.png"),
|
||||
width: 150,
|
||||
height: 150,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
Text(
|
||||
"SILAHKAN LOGIN",
|
||||
style: boldTextStyle.copyWith(
|
||||
fontSize: 18,
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 10,
|
||||
),
|
||||
MyTextFormField(
|
||||
hintText: "Username",
|
||||
prefixIcon: const Icon(Icons.person),
|
||||
controller: model.usernameController,
|
||||
validator:
|
||||
Validatorless.required("Username tidak boleh kosong"),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 10,
|
||||
),
|
||||
MyTextFormField(
|
||||
hintText: "Password",
|
||||
prefixIcon: const Icon(Icons.lock),
|
||||
controller: model.passwordController,
|
||||
obscureText: true,
|
||||
validator:
|
||||
Validatorless.required("Password tidak boleh kosong"),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 10,
|
||||
),
|
||||
SizedBox(
|
||||
width: MediaQuery.of(context).size.width * 0.5,
|
||||
child: MyButton(
|
||||
text: "LOGIN",
|
||||
onPressed: () {
|
||||
if (model.formKey.currentState!.validate()) {
|
||||
model.login();
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
model.navigationService
|
||||
.navigateTo(Routes.userIndexTrackingView);
|
||||
},
|
||||
child: const Text(
|
||||
"Kembali ke beranda",
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
// show the logo.png
|
||||
const Center(
|
||||
child: Image(
|
||||
image: AssetImage("assets/logo.png"),
|
||||
width: 150,
|
||||
height: 150,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
Text(
|
||||
"SILAHKAN LOGIN",
|
||||
style: boldTextStyle.copyWith(
|
||||
fontSize: 18,
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 10,
|
||||
),
|
||||
const MyTextFormField(
|
||||
hintText: "Username",
|
||||
prefixIcon: Icon(Icons.person),
|
||||
// controller: model.usernameController,
|
||||
),
|
||||
const SizedBox(
|
||||
height: 10,
|
||||
),
|
||||
const MyTextFormField(
|
||||
hintText: "Password",
|
||||
prefixIcon: Icon(Icons.lock),
|
||||
// controller: model.passwordController,
|
||||
),
|
||||
const SizedBox(
|
||||
height: 10,
|
||||
),
|
||||
SizedBox(
|
||||
width: MediaQuery.of(context).size.width * 0.5,
|
||||
child: MyButton(
|
||||
text: "LOGIN",
|
||||
onPressed: () {
|
||||
model.goToAdmin();
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
|
|
@ -1,13 +1,45 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
|
||||
import '../../../app/app.logger.dart';
|
||||
import '../../../app/app.router.dart';
|
||||
import '../../../app/core/custom_base_view_model.dart';
|
||||
|
||||
class LoginScreenViewModel extends CustomBaseViewModel {
|
||||
final log = getLogger('LoginScreenViewModel');
|
||||
final Future<SharedPreferences> _prefs = SharedPreferences.getInstance();
|
||||
Future<void> init() async {}
|
||||
|
||||
goToAdmin() {
|
||||
log.d('goToAdmin');
|
||||
navigationService.navigateTo(Routes.adminIndexTrackingView);
|
||||
final formKey = GlobalKey<FormState>();
|
||||
TextEditingController usernameController = TextEditingController();
|
||||
TextEditingController passwordController = TextEditingController();
|
||||
|
||||
login() {
|
||||
if (usernameController.text == 'admin' &&
|
||||
passwordController.text == 'admin') {
|
||||
_prefs.then((SharedPreferences prefs) {
|
||||
prefs.setBool('isLogin', true);
|
||||
prefs.setString('role', 'admin');
|
||||
});
|
||||
log.d('goToAdmin');
|
||||
navigationService.navigateTo(Routes.adminIndexTrackingView);
|
||||
} else if (usernameController.text == 'pimpinan' &&
|
||||
passwordController.text == 'pimpinan') {
|
||||
_prefs.then((SharedPreferences prefs) {
|
||||
prefs.setBool('isLogin', true);
|
||||
prefs.setString('role', 'pimpinan');
|
||||
});
|
||||
log.d('goToPimpinan');
|
||||
navigationService.navigateTo(Routes.pimpinanIndexTrackingView);
|
||||
} else {
|
||||
dialogService.showDialog(
|
||||
title: 'Gagal',
|
||||
description: 'Username atau password salah',
|
||||
);
|
||||
_prefs.then((SharedPreferences prefs) {
|
||||
prefs.setBool('isLogin', false);
|
||||
prefs.remove('role');
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,99 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:stacked/stacked.dart';
|
||||
import 'package:stacked_services/stacked_services.dart';
|
||||
import 'package:stylish_bottom_bar/model/bar_items.dart';
|
||||
import 'package:stylish_bottom_bar/stylish_bottom_bar.dart';
|
||||
|
||||
import '../../../../app/app.router.dart';
|
||||
import '../../../../app/themes/app_colors.dart';
|
||||
import '../../../../app/themes/app_text.dart';
|
||||
import './pimpinan_index_tracking_view_model.dart';
|
||||
|
||||
class PimpinanIndexTrackingView extends StatelessWidget {
|
||||
const PimpinanIndexTrackingView({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ViewModelBuilder<PimpinanIndexTrackingViewModel>.reactive(
|
||||
viewModelBuilder: () => PimpinanIndexTrackingViewModel(),
|
||||
onViewModelReady: (PimpinanIndexTrackingViewModel model) async {
|
||||
await model.init();
|
||||
},
|
||||
builder: (
|
||||
BuildContext context,
|
||||
PimpinanIndexTrackingViewModel model,
|
||||
Widget? child,
|
||||
) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text(
|
||||
model.header,
|
||||
style: const TextStyle(
|
||||
color: Colors.white,
|
||||
fontSize: 20,
|
||||
),
|
||||
),
|
||||
backgroundColor: mainColor,
|
||||
elevation: 0,
|
||||
automaticallyImplyLeading: false,
|
||||
actions: [
|
||||
IconButton(
|
||||
onPressed: () {
|
||||
// model.navigationService.navigateTo(Routes.loginScreenView);
|
||||
model.logout();
|
||||
},
|
||||
icon: const Icon(
|
||||
Icons.logout,
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
body: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 15),
|
||||
child: ExtendedNavigator(
|
||||
navigatorKey: StackedService.nestedNavigationKey(4),
|
||||
router: PimpinanIndexTrackingViewRouter(),
|
||||
initialRoute: PimpinanIndexTrackingViewRoutes.danaSosialAdminView,
|
||||
),
|
||||
),
|
||||
bottomNavigationBar: StylishBottomBar(
|
||||
items: [
|
||||
for (var item in model.bottomNavBarList)
|
||||
BottomBarItem(
|
||||
icon: Icon(item['icon'],
|
||||
color: model.currentIndex ==
|
||||
model.bottomNavBarList.indexOf(item)
|
||||
? sixthGrey
|
||||
: backgroundColor),
|
||||
title: Text(
|
||||
item['name'],
|
||||
style: regularTextStyle.copyWith(
|
||||
color: model.currentIndex ==
|
||||
model.bottomNavBarList.indexOf(item)
|
||||
? sixthGrey
|
||||
: Colors.grey,
|
||||
),
|
||||
),
|
||||
backgroundColor:
|
||||
model.currentIndex == model.bottomNavBarList.indexOf(item)
|
||||
? Colors.white
|
||||
: Colors.grey,
|
||||
),
|
||||
],
|
||||
currentIndex: model.currentIndex,
|
||||
hasNotch: true,
|
||||
backgroundColor: mainColor,
|
||||
onTap: (value) {
|
||||
model.handleNavigation(value);
|
||||
},
|
||||
option: BubbleBarOptions(
|
||||
barStyle: BubbleBarStyle.horizotnal,
|
||||
bubbleFillStyle: BubbleFillStyle.fill,
|
||||
opacity: 0.3),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,90 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
import 'package:stacked/stacked.dart';
|
||||
import 'package:stacked_services/stacked_services.dart';
|
||||
|
||||
import '../../../../app/app.locator.dart';
|
||||
import '../../../../app/app.logger.dart';
|
||||
import '../../../../app/app.router.dart';
|
||||
|
||||
class PimpinanIndexTrackingViewModel extends IndexTrackingViewModel {
|
||||
final log = getLogger('PimpinanIndexTrackingViewModel');
|
||||
final _navigationService = locator<NavigationService>();
|
||||
final _dialogService = locator<DialogService>();
|
||||
|
||||
final Future<SharedPreferences> _prefs = SharedPreferences.getInstance();
|
||||
|
||||
String header = 'Dana Sosial';
|
||||
|
||||
final _bottomNavBarList = [
|
||||
{
|
||||
'name': 'List',
|
||||
'icon': Icons.people_alt_outlined,
|
||||
'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,
|
||||
'header': 'Profil Panti Asuhan'
|
||||
},
|
||||
];
|
||||
|
||||
List<Map<String, dynamic>> get bottomNavBarList => _bottomNavBarList;
|
||||
final List<String> _views = [
|
||||
PimpinanIndexTrackingViewRoutes.dataSiswaView,
|
||||
PimpinanIndexTrackingViewRoutes.danaSosialAdminView,
|
||||
// PimpinanIndexTrackingViewRoutes.danaSosialKhususView,
|
||||
PimpinanIndexTrackingViewRoutes.profilView,
|
||||
];
|
||||
Future<void> init() async {
|
||||
_prefs.then((SharedPreferences prefs) {
|
||||
if (prefs.getString('role') == 'pimpinan') {
|
||||
setIndex(1);
|
||||
// // await 2 seconds to make sure the view is loaded
|
||||
// Future.delayed(const Duration(milliseconds: 500));
|
||||
} else {
|
||||
prefs.setBool('isLogin', false);
|
||||
prefs.remove('role');
|
||||
_navigationService.clearStackAndShow(Routes.loginScreenView);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void handleNavigation(int index) {
|
||||
log.d("handleNavigation: $index");
|
||||
log.d("currentIndex: $currentIndex");
|
||||
|
||||
if (currentIndex == index) return;
|
||||
|
||||
setIndex(index);
|
||||
header = _bottomNavBarList[index]['header'] as String;
|
||||
_navigationService.navigateTo(
|
||||
_views[index],
|
||||
id: 4,
|
||||
);
|
||||
}
|
||||
|
||||
logout() {
|
||||
_dialogService
|
||||
.showConfirmationDialog(
|
||||
title: 'Logout',
|
||||
description: 'Apakah anda yakin ingin logout?',
|
||||
cancelTitle: 'Ya',
|
||||
confirmationTitle: 'Tidak',
|
||||
// barrierDismissible: true,
|
||||
)
|
||||
.then((value) {
|
||||
if (!value!.confirmed) {
|
||||
_prefs.then((SharedPreferences prefs) {
|
||||
prefs.setBool('isLogin', false);
|
||||
prefs.remove('role');
|
||||
_navigationService.clearStackAndShow(Routes.loginScreenView);
|
||||
});
|
||||
} else {
|
||||
_navigationService.back();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
|
@ -1,3 +1,5 @@
|
|||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
|
||||
import '../../../app/app.logger.dart';
|
||||
import '../../../app/app.router.dart';
|
||||
import '../../../app/core/custom_base_view_model.dart';
|
||||
|
@ -7,8 +9,29 @@ class SplashScreenViewModel extends CustomBaseViewModel {
|
|||
Future<void> init() async {
|
||||
// wait 2 seconds then navigate to login
|
||||
await Future.delayed(const Duration(seconds: 2));
|
||||
await navigationService.navigateTo(
|
||||
Routes.loginScreenView,
|
||||
);
|
||||
prefs.then((SharedPreferences prefs) {
|
||||
if (prefs.getBool('isLogin') != true) {
|
||||
return navigationService.navigateTo(
|
||||
Routes.userIndexTrackingView,
|
||||
);
|
||||
}
|
||||
|
||||
if (prefs.getString('role') == 'admin') {
|
||||
return navigationService.navigateTo(
|
||||
Routes.adminIndexTrackingView,
|
||||
);
|
||||
}
|
||||
|
||||
if (prefs.getString('role') == 'pimpinan') {
|
||||
return navigationService.navigateTo(
|
||||
Routes.pimpinanIndexTrackingView,
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
// await navigationService.navigateTo(
|
||||
// // Routes.loginScreenView,
|
||||
// Routes.userIndexTrackingView,
|
||||
// );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,416 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:stacked/stacked.dart';
|
||||
import 'package:validatorless/validatorless.dart';
|
||||
|
||||
import '../../../app/themes/app_colors.dart';
|
||||
import '../../../app/themes/app_text.dart';
|
||||
import '../../widgets/my_button.dart';
|
||||
import '../../widgets/my_textformfield.dart';
|
||||
import './tambah_dana_sosial_view_model.dart';
|
||||
|
||||
class TambahDanaSosialView extends StatelessWidget {
|
||||
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(isKhusus);
|
||||
},
|
||||
builder: (
|
||||
BuildContext context,
|
||||
TambahDanaSosialViewModel model,
|
||||
Widget? child,
|
||||
) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: const Text(
|
||||
"Form Dana Sosial",
|
||||
style: TextStyle(
|
||||
color: Colors.white,
|
||||
fontSize: 20,
|
||||
),
|
||||
),
|
||||
backgroundColor: mainColor,
|
||||
elevation: 0,
|
||||
),
|
||||
body: Center(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 15),
|
||||
child: Form(
|
||||
key: model.formKey,
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
"Bentuk Donasi",
|
||||
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.bentukDonasi,
|
||||
onChanged: (String? newValue) {
|
||||
// model.setSelectedbentukDonasi(newValue!);
|
||||
model.log.i(newValue);
|
||||
model.bentukDonasi = newValue!;
|
||||
|
||||
model.notifyListeners();
|
||||
},
|
||||
items: model.bentukDonasiList.map((String value) {
|
||||
return DropdownMenuItem<String>(
|
||||
value: value,
|
||||
child: Text(
|
||||
value,
|
||||
style: regularTextStyle.copyWith(
|
||||
fontSize: 16,
|
||||
),
|
||||
),
|
||||
);
|
||||
}).toList(),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
Visibility(
|
||||
visible: model.bentukDonasi == 'Pemasukan',
|
||||
child: Text(
|
||||
"Nama Donator",
|
||||
style: regularTextStyle.copyWith(color: mainColor),
|
||||
),
|
||||
),
|
||||
Visibility(
|
||||
visible: model.bentukDonasi == 'Pemasukan' &&
|
||||
isKhusus == false,
|
||||
child: MyTextFormField(
|
||||
hintText: "Nama Donatur",
|
||||
controller: model.namaController,
|
||||
maxLines: 1,
|
||||
// validator: Validatorless.required(
|
||||
// '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),
|
||||
),
|
||||
Text(
|
||||
"Jenis Donasi / Pengeluaran",
|
||||
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.jenisDonasi,
|
||||
onChanged: (String? newValue) {
|
||||
// model.setSelectedjenisDonasi(newValue!);
|
||||
model.log.i(newValue);
|
||||
model.jenisDonasi = newValue!;
|
||||
model.notifyListeners();
|
||||
},
|
||||
items: model.jenisDonasiList.map((String value) {
|
||||
return DropdownMenuItem<String>(
|
||||
value: value,
|
||||
child: Text(
|
||||
value,
|
||||
style: regularTextStyle.copyWith(
|
||||
fontSize: 16,
|
||||
),
|
||||
),
|
||||
);
|
||||
}).toList(),
|
||||
),
|
||||
),
|
||||
),
|
||||
// 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),
|
||||
),
|
||||
Visibility(
|
||||
visible: model.jenisDonasi == 'Uang',
|
||||
child: Text(
|
||||
"Jumlah (Rp. )",
|
||||
style: regularTextStyle.copyWith(color: mainColor),
|
||||
),
|
||||
),
|
||||
Visibility(
|
||||
visible: model.jenisDonasi == 'Uang',
|
||||
child: MyTextFormField(
|
||||
hintText: "Jumlah (Rp. ) Donasi",
|
||||
keyboardType: TextInputType.number,
|
||||
controller: model.jumlahController,
|
||||
validator: model.jenisDonasi == 'Uang'
|
||||
? Validatorless.multiple(
|
||||
[
|
||||
Validatorless.required(
|
||||
'Jumlah tidak boleh kosong'),
|
||||
Validatorless.number('Jumlah harus angka'),
|
||||
],
|
||||
)
|
||||
: null,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
Text(
|
||||
"Tanggal",
|
||||
style: regularTextStyle.copyWith(color: mainColor),
|
||||
),
|
||||
MyTextFormField(
|
||||
hintText: ' Pilih Tanggal',
|
||||
readOnly: true,
|
||||
controller: model.tanggalController,
|
||||
validator: Validatorless.required(
|
||||
'Tanggal tidak boleh kosong'),
|
||||
onTap: () {
|
||||
model.changeDate(context);
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
Visibility(
|
||||
visible: model.jenisDonasi == 'Barang',
|
||||
child: Text(
|
||||
"Keterangan",
|
||||
style: regularTextStyle.copyWith(color: mainColor),
|
||||
),
|
||||
),
|
||||
Visibility(
|
||||
visible: model.jenisDonasi == 'Barang',
|
||||
child: MyTextFormField(
|
||||
hintText: 'Masukkan Keterangan',
|
||||
maxLines: 3,
|
||||
controller: model.keteranganController,
|
||||
validator: model.jenisDonasi == 'Barang'
|
||||
? Validatorless.multiple(
|
||||
[
|
||||
Validatorless.required(
|
||||
'Keterangan tidak boleh kosong'),
|
||||
],
|
||||
)
|
||||
: null,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
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();
|
||||
}
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,195 @@
|
|||
import 'package:dio/dio.dart';
|
||||
import 'package:flutter/material.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 '../../../services/http_services.dart';
|
||||
import '../../../services/my_easyloading.dart';
|
||||
|
||||
class TambahDanaSosialViewModel extends CustomBaseViewModel {
|
||||
final log = getLogger('TambahDanaSosialViewModel');
|
||||
final _httpService = locator<MyHttpServices>();
|
||||
final easyLoading = locator<MyEasyLoading>();
|
||||
|
||||
String bentukDonasi = 'Pemasukan';
|
||||
List<String> bentukDonasiList = ['Pemasukan', 'Pengeluaran'];
|
||||
|
||||
String jenisDonasi = 'Uang';
|
||||
List<String> jenisDonasiList = ['Uang', 'Barang'];
|
||||
|
||||
final formKey = GlobalKey<FormState>();
|
||||
|
||||
TextEditingController namaController = TextEditingController();
|
||||
TextEditingController jumlahController = TextEditingController();
|
||||
TextEditingController jumlahBarangController = TextEditingController();
|
||||
TextEditingController tanggalController = TextEditingController();
|
||||
TextEditingController keteranganController = TextEditingController();
|
||||
|
||||
// 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
|
||||
var datePicked = await showDatePicker(
|
||||
context: context,
|
||||
initialDate: DateTime.now(),
|
||||
firstDate: DateTime(2000),
|
||||
// last date is today's date
|
||||
lastDate: DateTime.now(),
|
||||
);
|
||||
|
||||
if (datePicked != null) {
|
||||
String date = datePicked.toString().split(' ')[0];
|
||||
tanggalController.text = date;
|
||||
}
|
||||
}
|
||||
|
||||
void addData() async {
|
||||
easyLoading.customLoading('Menambahkan data...');
|
||||
log.i(donaturSelectedIndex);
|
||||
try {
|
||||
var formData = FormData.fromMap({
|
||||
'bentuk': bentukDonasi,
|
||||
'nama': namaController.text,
|
||||
'jumlah': jumlahController.text,
|
||||
'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(
|
||||
!isKhusus ? 'dana_sosial' : 'dana_sosial_khusus', formData);
|
||||
log.i(response.data);
|
||||
easyLoading.showSuccess(" Data berhasil ditambahkan");
|
||||
navigationService.navigateTo(Routes.adminIndexTrackingView);
|
||||
} catch (e) {
|
||||
log.e(e);
|
||||
snackbarService.showSnackbar(
|
||||
message: 'Gagal menambahkan data',
|
||||
title: 'Error',
|
||||
duration: const Duration(seconds: 4),
|
||||
);
|
||||
} finally {
|
||||
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();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,95 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:panti_asuhan/app/app.router.dart';
|
||||
import 'package:stacked/stacked.dart';
|
||||
import 'package:stacked_services/stacked_services.dart';
|
||||
import 'package:stylish_bottom_bar/model/bar_items.dart';
|
||||
import 'package:stylish_bottom_bar/stylish_bottom_bar.dart';
|
||||
|
||||
import '../../../app/themes/app_colors.dart';
|
||||
import '../../../app/themes/app_text.dart';
|
||||
import './user_index_tracking_view_model.dart';
|
||||
|
||||
class UserIndexTrackingView extends StatelessWidget {
|
||||
const UserIndexTrackingView({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ViewModelBuilder<UserIndexTrackingViewModel>.reactive(
|
||||
viewModelBuilder: () => UserIndexTrackingViewModel(),
|
||||
onViewModelReady: (UserIndexTrackingViewModel model) async {
|
||||
await model.init();
|
||||
},
|
||||
builder: (
|
||||
BuildContext context,
|
||||
UserIndexTrackingViewModel model,
|
||||
Widget? child,
|
||||
) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text(
|
||||
model.header,
|
||||
style: const TextStyle(
|
||||
color: Colors.white,
|
||||
fontSize: 20,
|
||||
),
|
||||
),
|
||||
backgroundColor: mainColor,
|
||||
elevation: 0,
|
||||
automaticallyImplyLeading: false,
|
||||
actions: [
|
||||
IconButton(
|
||||
onPressed: () {
|
||||
model.login();
|
||||
},
|
||||
icon: const Icon(Icons.login, color: Colors.white),
|
||||
),
|
||||
],
|
||||
),
|
||||
body: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 15),
|
||||
child: ExtendedNavigator(
|
||||
navigatorKey: StackedService.nestedNavigationKey(5),
|
||||
router: UserIndexTrackingViewRouter(),
|
||||
initialRoute: UserIndexTrackingViewRoutes.danaSosialAdminView,
|
||||
),
|
||||
),
|
||||
bottomNavigationBar: StylishBottomBar(
|
||||
items: [
|
||||
for (var item in model.bottomNavBarList)
|
||||
BottomBarItem(
|
||||
icon: Icon(item['icon'],
|
||||
color: model.currentIndex ==
|
||||
model.bottomNavBarList.indexOf(item)
|
||||
? sixthGrey
|
||||
: backgroundColor),
|
||||
title: Text(
|
||||
item['name'],
|
||||
style: regularTextStyle.copyWith(
|
||||
color: model.currentIndex ==
|
||||
model.bottomNavBarList.indexOf(item)
|
||||
? sixthGrey
|
||||
: Colors.grey,
|
||||
),
|
||||
),
|
||||
backgroundColor:
|
||||
model.currentIndex == model.bottomNavBarList.indexOf(item)
|
||||
? Colors.white
|
||||
: Colors.grey,
|
||||
),
|
||||
],
|
||||
currentIndex: model.currentIndex,
|
||||
hasNotch: true,
|
||||
backgroundColor: mainColor,
|
||||
onTap: (value) {
|
||||
model.handleNavigation(value);
|
||||
},
|
||||
option: BubbleBarOptions(
|
||||
barStyle: BubbleBarStyle.horizotnal,
|
||||
bubbleFillStyle: BubbleFillStyle.fill,
|
||||
opacity: 0.3),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:panti_asuhan/app/app.router.dart';
|
||||
import 'package:stacked/stacked.dart';
|
||||
import 'package:stacked_services/stacked_services.dart';
|
||||
|
||||
import '../../../app/app.locator.dart';
|
||||
import '../../../app/app.logger.dart';
|
||||
|
||||
class UserIndexTrackingViewModel extends IndexTrackingViewModel {
|
||||
final log = getLogger('PimpinanIndexTrackingViewModel');
|
||||
final _navigationService = locator<NavigationService>();
|
||||
// final _dialogService = locator<DialogService>();
|
||||
|
||||
String header = 'Dana Sosial';
|
||||
|
||||
final _bottomNavBarList = [
|
||||
{
|
||||
'name': 'List',
|
||||
'icon': Icons.people_alt_outlined,
|
||||
'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,
|
||||
'header': 'Profil Panti Asuhan'
|
||||
},
|
||||
{'name': 'V & M', 'icon': Icons.list_alt_rounded, 'header': 'Visi & Misi'},
|
||||
{'name': 'Sejarah', 'icon': Icons.list_outlined, 'header': 'Sejarah'},
|
||||
{
|
||||
'name': 'S O',
|
||||
'icon': Icons.people_alt_outlined,
|
||||
'header': 'Struktur Organisasi'
|
||||
},
|
||||
];
|
||||
|
||||
List<Map<String, dynamic>> get bottomNavBarList => _bottomNavBarList;
|
||||
|
||||
final List<String> _views = [
|
||||
UserIndexTrackingViewRoutes.dataSiswaView,
|
||||
UserIndexTrackingViewRoutes.danaSosialAdminView,
|
||||
// UserIndexTrackingViewRoutes.danaSosialKhususView,
|
||||
UserIndexTrackingViewRoutes.profilView,
|
||||
UserIndexTrackingViewRoutes.visiMisiView,
|
||||
UserIndexTrackingViewRoutes.sejarahView,
|
||||
UserIndexTrackingViewRoutes.strukturOrganisasiView
|
||||
];
|
||||
|
||||
Future<void> init() async {
|
||||
setIndex(1);
|
||||
}
|
||||
|
||||
void handleNavigation(int index) {
|
||||
log.d("handleNavigation: $index");
|
||||
log.d("currentIndex: $currentIndex");
|
||||
|
||||
if (currentIndex == index) return;
|
||||
|
||||
setIndex(index);
|
||||
header = _bottomNavBarList[index]['header'] as String;
|
||||
_navigationService.navigateTo(
|
||||
_views[index],
|
||||
id: 5,
|
||||
);
|
||||
}
|
||||
|
||||
void login() {
|
||||
_navigationService.navigateTo(
|
||||
Routes.loginScreenView,
|
||||
);
|
||||
}
|
||||
}
|
|
@ -15,6 +15,12 @@ class MyTextFormField extends StatelessWidget {
|
|||
this.controller,
|
||||
this.maxLines = 1,
|
||||
this.onEditingComplete,
|
||||
this.readOnly = false,
|
||||
this.onTap,
|
||||
this.keyboardType = TextInputType.text,
|
||||
this.initialValue,
|
||||
this.enabled = true,
|
||||
this.maxLength,
|
||||
}) : super(key: key);
|
||||
|
||||
final String? labelText;
|
||||
|
@ -27,15 +33,27 @@ class MyTextFormField extends StatelessWidget {
|
|||
final TextEditingController? controller;
|
||||
final int maxLines;
|
||||
final VoidCallback? onEditingComplete;
|
||||
final bool readOnly;
|
||||
final VoidCallback? onTap;
|
||||
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,
|
||||
maxLines: maxLines,
|
||||
controller: controller,
|
||||
focusNode: focusNode,
|
||||
obscureText: obscureText ?? false,
|
||||
readOnly: readOnly,
|
||||
onTap: onTap,
|
||||
keyboardType: keyboardType,
|
||||
decoration: InputDecoration(
|
||||
prefixIcon: prefixIcon,
|
||||
suffixIcon: suffixIcon,
|
||||
|
|
|
@ -5,10 +5,10 @@
|
|||
import FlutterMacOS
|
||||
import Foundation
|
||||
|
||||
import location
|
||||
import path_provider_foundation
|
||||
import shared_preferences_foundation
|
||||
|
||||
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
||||
LocationPlugin.register(with: registry.registrar(forPlugin: "LocationPlugin"))
|
||||
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
|
||||
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
|
||||
}
|
||||
|
|
122
pubspec.lock
|
@ -33,6 +33,14 @@ packages:
|
|||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.10.0"
|
||||
auto_size_text:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: auto_size_text
|
||||
sha256: "3f5261cd3fb5f2a9ab4e2fc3fba84fd9fcaac8821f20a1d4e71f557521b22599"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.0"
|
||||
boolean_selector:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -246,6 +254,22 @@ 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:
|
||||
name: flutter_holo_date_picker
|
||||
sha256: "94cf29471ffac123043745b65c690dcf6d481e98c11bda71f78a34dd6f726247"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.0"
|
||||
flutter_lints:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
|
@ -361,7 +385,7 @@ packages:
|
|||
source: hosted
|
||||
version: "3.2.1"
|
||||
http_parser:
|
||||
dependency: transitive
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: http_parser
|
||||
sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b"
|
||||
|
@ -408,6 +432,14 @@ packages:
|
|||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.6.3"
|
||||
intl:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: intl
|
||||
sha256: "3bc132a9dbce73a7e4a21a17d06e1878839ffbf975568bc875c60537824b0c4d"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.18.1"
|
||||
io:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -440,30 +472,6 @@ packages:
|
|||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.1"
|
||||
location:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: location
|
||||
sha256: "9051959f6f2ccadd887b28b66e9cbbcc25b6838e37cf9e894c421ccc0ebf80b5"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.4.0"
|
||||
location_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: location_platform_interface
|
||||
sha256: "62eeaf1658e92e4459b727f55a3c328eccbac8ba043fa6d262ac5286ad48384c"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.3.0"
|
||||
location_web:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: location_web
|
||||
sha256: "6c08c408a040534c0269c4ff9fe17eebb5a36dea16512fbaf116b9c8bc21545b"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.1.1"
|
||||
logger:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -664,6 +672,62 @@ packages:
|
|||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.1.0"
|
||||
shared_preferences:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: shared_preferences
|
||||
sha256: "0344316c947ffeb3a529eac929e1978fcd37c26be4e8468628bac399365a3ca1"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.2.0"
|
||||
shared_preferences_android:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shared_preferences_android
|
||||
sha256: fe8401ec5b6dcd739a0fe9588802069e608c3fdbfd3c3c93e546cf2f90438076
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.2.0"
|
||||
shared_preferences_foundation:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shared_preferences_foundation
|
||||
sha256: f39696b83e844923b642ce9dd4bd31736c17e697f6731a5adf445b1274cf3cd4
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.3.2"
|
||||
shared_preferences_linux:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shared_preferences_linux
|
||||
sha256: "71d6806d1449b0a9d4e85e0c7a917771e672a3d5dc61149cc9fac871115018e1"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.3.0"
|
||||
shared_preferences_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shared_preferences_platform_interface
|
||||
sha256: "23b052f17a25b90ff2b61aad4cc962154da76fb62848a9ce088efe30d7c50ab1"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.3.0"
|
||||
shared_preferences_web:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shared_preferences_web
|
||||
sha256: "7347b194fb0bbeb4058e6a4e87ee70350b6b2b90f8ac5f8bd5b3a01548f6d33a"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.2.0"
|
||||
shared_preferences_windows:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shared_preferences_windows
|
||||
sha256: f95e6a43162bce43c9c3405f3eb6f39e5b5d11f65fab19196cf8225e2777624d
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.3.0"
|
||||
shelf:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -813,6 +877,14 @@ packages:
|
|||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.2.0"
|
||||
validatorless:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: validatorless
|
||||
sha256: ddb46df636114b3322d289489164cac309767b157191ba43c7ad49b28c2b57c7
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.2.3"
|
||||
vector_graphics:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
11
pubspec.yaml
|
@ -42,10 +42,18 @@ dependencies:
|
|||
path_provider: ^2.0.9
|
||||
dio:
|
||||
flutter_easyloading:
|
||||
location: ^4.4.0
|
||||
# location: ^4.4.0
|
||||
google_fonts:
|
||||
flutter_svg:
|
||||
stylish_bottom_bar: ^1.0.0
|
||||
# calendar_date_picker2: ^0.5.2
|
||||
flutter_holo_date_picker: ^1.1.0
|
||||
validatorless: ^1.2.3
|
||||
intl:
|
||||
shared_preferences:
|
||||
# flutter_hooks:
|
||||
http_parser:
|
||||
flutter_file_downloader: ^1.2.1
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
|
@ -75,6 +83,7 @@ flutter:
|
|||
assets:
|
||||
- .env
|
||||
- assets/logo.png
|
||||
- assets/qrcode.png
|
||||
# - images/a_dot_ham.jpeg
|
||||
|
||||
# An image asset can refer to one or more resolution-specific "variants", see
|
||||
|
|