step 3 : copy login screen app dokter

This commit is contained in:
sindhu
2024-01-12 14:22:49 +07:00
parent b4500de798
commit 3ae6622951
16 changed files with 2143 additions and 0 deletions

View File

@@ -0,0 +1,103 @@
import 'package:intl/intl.dart';
extension AppStringExtension on String {
String currencyFormat() {
final numberFormat = NumberFormat.currency(
locale: 'id_ID',
decimalDigits: 0,
symbol: 'Rp ',
);
return numberFormat.format(double.parse(this));
}
String dateFormat() {
final dateFormatFromApi = DateFormat('yyyy-M-dd hh:mm:ss');
// final dateFormat = DateFormat('dd MMM yyyy');
final dateFormat = DateFormat('dd/M/yy');
return dateFormat.format(dateFormatFromApi.parse(this));
}
String dateFormatdmy() {
final dateFormatFromApi = DateFormat('yyyy-M-dd hh:mm:ss');
// final dateFormat = DateFormat('dd MMM yyyy');
final dateFormat = DateFormat('dd-MM-yyyy hh:mm:ss');
return dateFormat.format(dateFormatFromApi.parse(this));
}
String dateFormatdmyHistorical() {
final dateFormatFromApi = DateFormat('yyyy-MM-dd');
// final dateFormat = DateFormat('dd MMM yyyy');
final dateFormat = DateFormat('dd-MM-yyyy');
return dateFormat.format(dateFormatFromApi.parse(this));
}
}
String formatBulanIndo(String tanggal) {
DateTime dateTime = DateFormat("yyyy-MM-dd").parse(tanggal);
var m = DateFormat('MM').format(dateTime);
var month = "";
switch (m) {
case '01':
{
month = "Januari";
}
break;
case '02':
{
month = "Februari";
}
break;
case '03':
{
month = "Maret";
}
break;
case '04':
{
month = "April";
}
break;
case '05':
{
month = "Mei";
}
break;
case '06':
{
month = "Juni";
}
break;
case '07':
{
month = "Juli";
}
break;
case '08':
{
month = "Agustus";
}
break;
case '09':
{
month = "September";
}
break;
case '10':
{
month = "Oktober";
}
break;
case '11':
{
month = "November";
}
break;
case '12':
{
month = "Desember";
}
break;
}
return month;
}

View File

@@ -0,0 +1,556 @@
// ignore_for_file: prefer_const_constructors, non_constant_identifier_names
import 'package:flutter/material.dart';
class Constant {
static double designHeight = 1024;
static double designWidth = 1440;
static double designHeightPhone = 844;
static double designWidthPhone = 390;
static String bearerName = "petty-cash";
static String version = "2.00";
// static String baseUrl = "https://devregonline.pramita.co.id/one-api/xdoc/";
// tester devbandungraya
static String baseUrl =
"http://devbandungraya.aplikasi.web.id/one-api-doctor/doctor_mitra/";
static String baseUrl_appdoctor =
"http://devbandungraya.aplikasi.web.id/one-api/app_doctor/";
// * surabaya
// static String baseUrl =
// "http://surabaya.bisone.pramitalab.id/one-api-doctor/doctor_mitra/";
// static String baseUrl_appdoctor =
// "http://surabaya.bisone.pramitalab.id/one-api/app_doctor/";
// * jakarta
// static String baseUrl =
// "http://jakarta.bisone2.pramitalab.id/one-api-doctor/doctor_mitra/";
// static String baseUrl_appdoctor =
// "http://jakarta.bisone2.pramitalab.id/one-api/app_doctor/";
// * bandung
// static String baseUrl =
// "http://bandung.bisone3.pramitalab.id/one-api-doctor/doctor_mitra/";
// static String baseUrl_appdoctor =
// "http://bandung.bisone3.pramitalab.id/one-api/app_doctor/";
// * salatiga
// static String baseUrl =
// "http://salatigaraya.bisone7.pramitalab.id/one-api-doctor/doctor_mitra/";
// static String baseUrl_appdoctor =
// "http://salatigaraya.bisone7.pramitalab.id/one-api/app_doctor/";
// * semarang
// static String baseUrl =
// "http://semarang.bisone7.pramitalab.id/one-api-doctor/doctor_mitra/";
// static String baseUrl_appdoctor =
// "http://semarang.bisone7.pramitalab.id/one-api/app_doctor/";
// * magelang
// static String baseUrl =
// "http://magelang.bisone7.pramitalab.id/one-api-doctor/doctor_mitra/";
// static String baseUrl_appdoctor =
// "http://magelang.bisone7.pramitalab.id/one-api/app_doctor/";
// // * tegal
// static String baseUrl =
// "http://tegal.bisone7.pramitalab.id/one-api-doctor/doctor_mitra/";
// static String baseUrl_appdoctor =
// "http://tegal.bisone7.pramitalab.id/one-api/app_doctor/";
// // * cirebon
// static String baseUrl =
// "http://cirebon.bisone4.pramitalab.id/one-api-doctor/doctor_mitra/";
// static String baseUrl_appdoctor =
// "http://cirebon.bisone4.pramitalab.id/one-api/app_doctor/";
// // * tasik
// static String baseUrl =
// "http://tasikmalaya.bisone2.pramitalab.id/one-api-doctor/doctor_mitra/";
// static String baseUrl_appdoctor =
// "http://tasikmalaya.bisone2.pramitalab.id/one-api/app_doctor/";
// // * jogja
// static String baseUrl =
// "http://jogja.bisone.pramitalab.id/one-api-doctor/doctor_mitra/";
// static String baseUrl_appdoctor =
// "http://jogja.bisone.pramitalab.id/one-api/app_doctor/";
// // * bali
// static String baseUrl =
// "http://bali.bisone.pramitalab.id/one-api-doctor/doctor_mitra/";
// static String baseUrl_appdoctor =
// "http://bali.bisone.pramitalab.id/one-api/app_doctor/";
// // * medan
// static String baseUrl =
// "http://medan.bisone4.pramitalab.id/one-api-doctor/doctor_mitra/";
// static String baseUrl_appdoctor =
// "http://medan.bisone4.pramitalab.id/one-api/app_doctor/";
// // * palembang
// static String baseUrl =
// "http://palembang.bisone5.pramitalab.id/one-api-doctor/doctor_mitra/";
// static String baseUrl_appdoctor =
// "http://palembang.bisone5.pramitalab.id/one-api/app_doctor/";
// // * pontianak
// static String baseUrl =
// "http://pontianakraya.bisone2.pramitalab.id/one-api-doctor/doctor_mitra/";
// static String baseUrl_appdoctor =
// "http://pontianakraya.bisone2.pramitalab.id/one-api/app_doctor/";
// // * balikpapan
// static String baseUrl =
// "http://balikpapan.bisone2.pramitalab.id/one-api-doctor/doctor_mitra/";
// static String baseUrl_appdoctor =
// "http://balikpapan.bisone2.pramitalab.id/one-api/app_doctor/";
// // * padang
// static String baseUrl =
// "http://padang.bisone4.pramitalab.id/one-api-doctor/doctor_mitra/";
// static String baseUrl_appdoctor =
// "http://padang.bisone4.pramitalab.id/one-api/app_doctor/";
// // * pekanbaru
// static String baseUrl =
// "http://pekanbaru.bisone4.pramitalab.id/one-api-doctor/doctor_mitra/";
// static String baseUrl_appdoctor =
// "http://pekanbaru.bisone4.pramitalab.id/one-api/app_doctor/";
// // * makassar
// static String baseUrl =
// "http://makassar.bisone2.pramitalab.id/one-api-doctor/doctor_mitra/";
// static String baseUrl_appdoctor =
// "http://makassar.bisone2.pramitalab.id/one-api/app_doctor/";
// // * manado
// static String baseUrl =
// "http://manado.bisone2.pramitalab.id/one-api-doctor/doctor_mitra/";
// static String baseUrl_appdoctor =
// "http://manado.bisone2.pramitalab.id/one-api/app_doctor/";
// * bekasi
// static String baseUrl =
// "http://bekasiraya.bisone2.pramitalab.id/one-api-doctor/doctor_mitra/";
// static String baseUrl_appdoctor =
// "http://bekasiraya.bisone2.pramitalab.id/one-api/app_doctor/";
//color Theme
// login marketing
static Color subTitleBlack = const Color(0xff000000);
static Color backgroundColor = const Color(0xffFFFFFF);
static Color buttonLoginBackgroundColor = const Color(0xffE61301);
static Color buttonRedBackgroundColor = const Color(0xffd90504);
static Color textLoginColor = const Color(0xffFFFFFF);
static Color shadowLoginMarketing = Colors.grey.withOpacity(0.3);
static Color boxDecorationShadowLoginMaketing = Colors.blueGrey;
static Color textRedProblemMaketing = const Color(0xffE61301);
// home
static Color backgroundColorWelcome = const Color(0xffE61301);
static Color textMonthToDate = const Color(0xff80848E);
static Color textListStatusOrder = const Color(0xff070708);
static Color confirmed = const Color(0xff0BAF48);
static Color backgroundTotalOrderRight = const Color(0xffF6F5F5);
static Color dividerHorizontal = const Color(0xffF4F6F8);
static Color backgroundTopHome = const Color(0xffFEF0EB);
// order detail
static Color textOrderDetail = const Color(0xff7E7F81);
static Color cardConfirmed = const Color(0xffEBF9F0);
static Color cardUnconfirmed = const Color(0xffFEF0EB);
static Color textDropdown = const Color(0xff282828);
// pendaftaran Pasien
static Color textCardPendaftaranPasien = const Color(0xff2E2D2D);
// static Color cardColorPendaftaranPasien = const Color(0xffFDFDFD);
static Color cardColorPendaftaranPasien = const Color(0xffF4F6F8);
static Color floatingbg = const Color(0xffDC2626);
// pendaftaran pasien - demografi
static Color backgroundCardNetral1_100 = const Color(0xffD1D2D6);
static Color backgroundCardGreen_600 = const Color(0xff0BAF48);
// divider
static Color dividerColor = Color(0xffD1D2D6);
// grey
static Color greyColor = Color(0xff80848E);
static Color chipText = Color(0xff637381);
// chip bg color
static Color chipBg = Color(0xffEDEFF2);
// checkbox color
static Color checkboxActive = Colors.red;
static Color checkboxCheck = Colors.white;
static Color checkboxSelected = Colors.red.shade100;
// icon file
static Color fileColor = Color(0xFF087D33);
// fixing color
static Color red_100 = Color(0xffFFB9B3);
static Color red_200 = Color(0xffFE8A80);
static Color red_300 = Color(0xffFE5B4D);
static Color red_400 = Color(0xffFE2C1A);
static Color red_500 = Color(0xffE61301);
static Color red_600 = Color(0xffB20F01);
static Color red_700 = Color(0xff7F0A01);
static Color red_800 = Color(0xff4C0600);
static Color red_900 = Color(0xff190200);
static Color green_100 = Color(0xffBCFBD3);
static Color green_200 = Color(0xff8CF8B4);
static Color green_300 = Color(0xff5CF595);
static Color green_400 = Color(0xff2CF275);
static Color green_500 = Color(0xff0EDD5B);
static Color green_600 = Color(0xff0BAF48);
static Color green_700 = Color(0xff087D33);
static Color green_800 = Color(0xff054D20);
static Color green_900 = Color(0xff021D0C);
static Color netral_100 = Color(0xffD1D2D6);
static Color netral_200 = Color(0xffB6B8BE);
static Color netral_300 = Color(0xff9B9EA6);
static Color netral_400 = Color(0xff80848E);
static Color netral_500 = Color(0xff676A74);
static Color netral_600 = Color(0xff4F5259);
static Color netral_700 = Color(0xff37393E);
static Color netral_800 = Color(0xff1F2023);
static Color netral_900 = Color(0xff070708);
static Color white = Color(0xffFDFDFD);
static Color textBlack = Color(0xff070708);
static Color textRed = Color(0xffE61301);
static Color textGrey = Color(0xff80848E);
static Color textWhite = Color(0xffFDFDFD);
static Color textGreen = Color(0xff0BAF48);
//typoGraphy
static TextStyle titleH1Login({required BuildContext context}) {
return TextStyle(
fontSize: Constant.getActualYPhone(context: context, y: 24),
fontWeight: FontWeight.w700,
);
}
static TextStyle titleH3_700({required BuildContext context}) {
return TextStyle(
fontSize: Constant.getActualYPhone(context: context, y: 24),
fontWeight: FontWeight.w700,
);
}
static TextStyle titleH3_700V2({required BuildContext context}) {
return TextStyle(
fontSize: Constant.getActualYPhone(context: context, y: 32),
fontWeight: FontWeight.w700,
);
}
static TextStyle titleH3_700GantiPassword({required BuildContext context}) {
return TextStyle(
fontSize: Constant.getActualYPhone(context: context, y: 14),
fontWeight: FontWeight.w500,
);
}
static TextStyle titleH3_700SignOut({required BuildContext context}) {
return TextStyle(
fontSize: Constant.getActualYPhone(context: context, y: 30),
fontWeight: FontWeight.w600,
);
}
static TextStyle titleH4Login({required BuildContext context}) {
return TextStyle(
fontSize: Constant.getActualYPhone(context: context, y: 16),
fontWeight: FontWeight.w400,
);
}
// homescreen
static TextStyle titleLast30Days({required BuildContext context}) {
return TextStyle(
fontSize: Constant.getActualYPhone(context: context, y: 16),
fontWeight: FontWeight.w700,
);
}
static TextStyle titleH4_500({required BuildContext context}) {
return TextStyle(
fontSize: Constant.getActualYPhone(context: context, y: 20),
fontWeight: FontWeight.w500,
);
}
static TextStyle H4_500({required BuildContext context}) {
return TextStyle(
fontSize: Constant.getActualYPhone(context: context, y: 20),
fontWeight: FontWeight.w500,
);
}
static TextStyle H4_600({required BuildContext context}) {
return TextStyle(
fontSize: Constant.getActualYPhone(context: context, y: 20),
fontWeight: FontWeight.w600,
);
}
static TextStyle H4_700V2({required BuildContext context}) {
return TextStyle(
fontSize: Constant.getActualYPhone(context: context, y: 28),
fontWeight: FontWeight.w700,
);
}
static TextStyle titleH5({required BuildContext context}) {
return TextStyle(
fontSize: Constant.getActualYPhone(context: context, y: 18),
fontWeight: FontWeight.w500,
);
}
static TextStyle caption1_400({required BuildContext context}) {
return TextStyle(
fontSize: Constant.getActualYPhone(context: context, y: 11),
fontWeight: FontWeight.w400,
);
}
static TextStyle caption3_500({required BuildContext context}) {
return TextStyle(
fontSize: Constant.getActualYPhone(context: context, y: 9),
fontWeight: FontWeight.w500,
);
}
static TextStyle titleH2({required BuildContext context}) {
return TextStyle(
fontSize: Constant.getActualYPhone(context: context, y: 32),
fontWeight: FontWeight.w500,
);
}
static TextStyle titleH1_600({required BuildContext context}) {
return TextStyle(
fontSize: Constant.getActualYPhone(context: context, y: 36),
fontWeight: FontWeight.w600,
);
}
static TextStyle body3({required BuildContext context}) {
return TextStyle(
fontSize: Constant.getActualYPhone(context: context, y: 12),
fontWeight: FontWeight.w400,
);
}
static TextStyle body1({required BuildContext context}) {
return TextStyle(
fontSize: Constant.getActualYPhone(context: context, y: 16),
fontWeight: FontWeight.w500,
);
}
static TextStyle body1_400({required BuildContext context}) {
return TextStyle(
fontSize: Constant.getActualYPhone(context: context, y: 16),
fontWeight: FontWeight.w400,
);
}
static TextStyle body1_400_dibulan({required BuildContext context}) {
return TextStyle(
fontSize: Constant.getActualYPhone(context: context, y: 14),
fontWeight: FontWeight.w400,
);
}
static TextStyle body1_600({required BuildContext context}) {
return TextStyle(
fontSize: Constant.getActualYPhone(context: context, y: 16),
fontWeight: FontWeight.w600,
);
}
static TextStyle body1_500({required BuildContext context}) {
return TextStyle(
fontSize: Constant.getActualYPhone(context: context, y: 16),
fontWeight: FontWeight.w500,
);
}
static TextStyle body2_400({required BuildContext context}) {
return TextStyle(
fontSize: Constant.getActualYPhone(context: context, y: 14),
fontWeight: FontWeight.w400,
);
}
static TextStyle titleH3({required BuildContext context}) {
return TextStyle(
fontSize: Constant.getActualYPhone(context: context, y: 24),
fontWeight: FontWeight.w500,
);
}
static TextStyle titleH3_600({required BuildContext context}) {
return TextStyle(
fontSize: Constant.getActualYPhone(context: context, y: 24),
fontWeight: FontWeight.w600,
);
}
static TextStyle H3_600({required BuildContext context}) {
return TextStyle(
fontSize: Constant.getActualYPhone(context: context, y: 24),
fontWeight: FontWeight.w600,
);
}
static TextStyle H3_500({required BuildContext context}) {
return TextStyle(
fontSize: Constant.getActualYPhone(context: context, y: 24),
fontWeight: FontWeight.w500,
);
}
static TextStyle H5_500({required BuildContext context}) {
return TextStyle(
fontSize: Constant.getActualYPhone(context: context, y: 18),
fontWeight: FontWeight.w500,
);
}
static TextStyle body2({required BuildContext context}) {
return TextStyle(
fontSize: Constant.getActualYPhone(context: context, y: 14),
fontWeight: FontWeight.w400,
);
}
static TextStyle body2_500({required BuildContext context}) {
return TextStyle(
fontSize: Constant.getActualYPhone(context: context, y: 14),
fontWeight: FontWeight.w400,
);
}
static TextStyle body2_500_italic({required BuildContext context}) {
return TextStyle(
fontSize: Constant.getActualYPhone(context: context, y: 14),
fontWeight: FontWeight.w400,
fontStyle: FontStyle.italic);
}
static TextStyle body1_700({required BuildContext context}) {
return TextStyle(
fontSize: Constant.getActualYPhone(context: context, y: 16),
fontWeight: FontWeight.w700,
);
}
static TextStyle H3_700({required BuildContext context}) {
return TextStyle(
fontSize: Constant.getActualYPhone(context: context, y: 24),
fontWeight: FontWeight.w700,
);
}
static TextStyle body3_400({required BuildContext context}) {
return TextStyle(
fontSize: Constant.getActualYPhone(context: context, y: 12),
fontWeight: FontWeight.w400,
);
}
static TextStyle body3_500({required BuildContext context}) {
return TextStyle(
fontSize: Constant.getActualYPhone(context: context, y: 12),
fontWeight: FontWeight.w500,
);
}
static TextStyle titleH7_700({required BuildContext context}) {
return TextStyle(
fontSize: Constant.getActualYPhone(context: context, y: 12),
fontWeight: FontWeight.w700,
);
}
// pendaftaran pasien
static TextStyle titleH5_600({required BuildContext context}) {
return TextStyle(
fontSize: Constant.getActualYPhone(context: context, y: 18),
fontWeight: FontWeight.w600,
);
}
// demografi
static TextStyle body2_600({required BuildContext context}) {
return TextStyle(
fontSize: Constant.getActualYPhone(context: context, y: 14),
fontWeight: FontWeight.w600,
);
}
//size convertion
static double getActualX({
required BuildContext context,
required double x,
}) {
return x / designWidth * MediaQuery.of(context).size.width;
}
static double getActualY({
required BuildContext context,
required double y,
}) {
return y / designHeight * MediaQuery.of(context).size.height;
}
static double getActualXPhone({
required BuildContext context,
required double x,
}) {
return x / designWidthPhone * MediaQuery.of(context).size.width;
}
static double getActualYPhone({
required BuildContext context,
required double y,
}) {
return y / designHeightPhone * MediaQuery.of(context).size.height;
}
}

View File

@@ -0,0 +1,19 @@
import 'package:flutter/material.dart';
import '../screen/login/login_screen.dart';
const loginRoute = "/loginRoute";
const menuRoute = "/menuRoute";
class AppRoute {
static Route<dynamic> generateRoute(RouteSettings settings) {
// default
return MaterialPageRoute(builder: (context) {
return MediaQuery(
data: MediaQuery.of(context)
.copyWith(textScaleFactor: 1.0, padding: const EdgeInsets.all(0)),
child: const LoginScreen(),
);
});
}
}

View File

@@ -0,0 +1,72 @@
class AuthModel {
final String token;
final AuthDoctorModel model;
AuthModel({
required this.token,
required this.model,
});
}
class AuthDoctorModel {
// "M_UserID": "1",
// "M_UserUsername": "alhadad",
// "M_UserM_DoctorCode": "3101210841",
// "M_UserM_DoctorID": "9562",
// "M_UserM_StaffID": "376",
// "ip": "139.194.156.91",
// "agent": "PostmanRuntime/7.29.2"
late String doctorID;
late String doctorName;
// new
late String M_UserID;
late String M_UserUsername;
late String M_UserM_DoctorCode;
late String M_UserM_DoctorID;
late String M_UserM_StaffID;
late String M_UserM_MouID;
late String ip;
late String agent;
AuthDoctorModel({
// required this.doctorID,
// required this.doctorName,
required this.M_UserID,
required this.M_UserUsername,
required this.M_UserM_DoctorCode,
required this.M_UserM_DoctorID,
this.M_UserM_StaffID = "",
this.M_UserM_MouID = "",
this.ip = "",
this.agent = ""
});
AuthDoctorModel.fromJson(Map<String, dynamic> json) {
M_UserID = json['M_UserID'].toString();
M_UserUsername = json['M_UserUsername'].toString();
M_UserM_DoctorCode = json['M_UserM_DoctorCode'].toString();
M_UserM_DoctorID = json['M_UserM_DoctorID'].toString();
M_UserM_StaffID = json['M_UserM_StaffID'].toString();
M_UserM_MouID = json['M_UserM_MouID'].toString();
ip = json['ip'].toString();
agent = json['agent'].toString();
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
data['M_UserID'] = M_UserID;
data['M_UserUsername'] = M_UserUsername;
data['M_UserM_DoctorCode'] = M_UserM_DoctorCode;
data['M_UserM_DoctorID'] = M_UserM_DoctorID;
data['M_UserM_StaffID'] = M_UserM_StaffID;
data['M_UserM_MouID'] = M_UserM_MouID;
data['ip'] = ip;
data['agent'] = agent;
return data;
}
}

View File

@@ -0,0 +1,3 @@
import 'package:flutter_riverpod/flutter_riverpod.dart';
final currentPageProvider = StateProvider<int?>((ref) => null);

View File

@@ -0,0 +1,4 @@
import 'package:flutter_riverpod/flutter_riverpod.dart';
import '../model/auth_model.dart';
final currentUserProvider = StateProvider<AuthModel?>((ref) => null);

View File

@@ -0,0 +1,4 @@
import 'package:dio/dio.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
final dioProvider = Provider<Dio>((ref) => Dio());

View File

@@ -0,0 +1,90 @@
import '../app/constant.dart';
import '../model/auth_model.dart';
import 'base_repository.dart';
class AuthRepository extends BaseRepository {
AuthRepository({required super.dio});
Future<AuthModel> login({
required String username,
required String dokterId,
required String password,
}) async {
final param = {
"username": username,
"doctor_id": dokterId,
"password": password
// "username": "alhadad1",
// "doctor_id": "2891",
// "password": "3"
};
// final service = "${Constant.baseUrl}xauth/login";
final service = "${Constant.baseUrl}auth/login";
final resp = await post(param: param, service: service);
final result = AuthModel(
token: resp["data"]["token"],
model: AuthDoctorModel.fromJson(resp["data"]["user"]),
);
return result;
}
Future<String> logout({
required String M_UserID,
required String M_UserUsername,
}) async {
final param = {
"M_UserID": M_UserID,
"M_UserUsername": M_UserUsername
// "username": "alhadad",
// "doctor_id": "3101210841",
// "password": "riau123"
};
final service = "${Constant.baseUrl}auth/logout";
final resp = await post(param: param, service: service);
if (resp["status"] == "OK") {
return resp['status'];
} else {
return resp['message'];
}
}
Future<String> change_password({
required String token,
required String M_UserID,
required String username,
required String doctor_id,
required String new_password,
required String confirm_password,
}) async {
final param = {
"token": token,
"M_UserID": M_UserID,
"username": username,
"doctor_id": doctor_id,
"new_password": new_password,
"confirm_password": confirm_password
// "username": "alhadad",
// "doctor_id": "3101210841",
// "password": "riau123"
};
final service = "${Constant.baseUrl}auth/change_password";
final resp = await post(param: param, service: service);
// final result = AuthModel(
// token: resp["data"]["token"],
// model: AuthDoctorModel.fromJson(resp["data"]["user"]),
// );
// return result;
if (resp["status"] == "OK") {
return resp['message'];
} else {
return resp['message'];
}
}
}

View File

@@ -0,0 +1,104 @@
import 'dart:convert';
import 'dart:io';
import 'package:dio/dio.dart';
abstract class BaseRepository {
final Dio dio;
BaseRepository({required this.dio});
Future<Map<String, dynamic>> post({
required Map<String, dynamic> param,
required String service,
String? token,
}) async {
try {
final response = await dio.post(
// Constant.baseUrl + service,
service,
data: jsonEncode(param),
options: Options(
headers: token != null
? {
HttpHeaders.contentTypeHeader: "application/json",
HttpHeaders.authorizationHeader: "Bearer $token",
}
: {
HttpHeaders.contentTypeHeader: "application/json",
},
contentType: "application/json",
),
);
if (response.statusCode != 200) {
throw BaseRepositoryException(
message: "Invalid Http Response ${response.statusCode}",
);
}
Map<String, dynamic> jsonData = jsonDecode(response.data);
if (jsonData["status"] != "OK") {
throw BaseRepositoryException(
message: jsonData["message"],
);
} else {
return jsonData;
}
} on DioError catch (e) {
throw BaseRepositoryException(message: e.message);
} on SocketException catch (e) {
throw BaseRepositoryException(message: e.message);
} on BaseRepositoryException catch (e) {
throw BaseRepositoryException(message: e.message);
}
}
Future<Map<String, dynamic>> get({
// required Map<String, dynamic> param,
required String service,
String? token,
}) async {
try {
final response = await dio.post(
// Constant.baseUrl + service,
service,
// data: jsonEncode(param),
options: Options(
headers: token != null
? {
HttpHeaders.contentTypeHeader: "application/json",
HttpHeaders.authorizationHeader: "Bearer $token",
}
: {
HttpHeaders.contentTypeHeader: "application/json",
},
contentType: "application/json",
),
);
if (response.statusCode != 200) {
throw BaseRepositoryException(
message: "Invalid Http Response ${response.statusCode}",
);
}
Map<String, dynamic> jsonData = jsonDecode(response.data);
if (jsonData["status"] != "OK") {
throw BaseRepositoryException(
message: jsonData["message"],
);
} else {
return jsonData;
}
} on DioError catch (e) {
throw BaseRepositoryException(message: e.message);
} on SocketException catch (e) {
throw BaseRepositoryException(message: e.message);
} on BaseRepositoryException catch (e) {
throw BaseRepositoryException(message: e.message);
}
}
}
class BaseRepositoryException implements Exception {
final String message;
BaseRepositoryException({
required this.message,
});
}

View File

@@ -0,0 +1,278 @@
// ignore_for_file: prefer_const_constructors, use_full_hex_values_for_flutter_colors
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import '../../app/constant.dart';
import '../../app/route.dart';
import '../../provider/current_menu_provider.dart';
import '../../provider/current_user_provider.dart';
import 'custom_text_field.dart';
import 'login_provider.dart';
class BlockBody extends HookConsumerWidget {
const BlockBody({
Key? key,
}) : super(key: key);
@override
Widget build(BuildContext context, WidgetRef ref) {
final isPasswordObscured = useState<bool>(true);
final ctrlUsername = useTextEditingController(text: "");
final ctrlDokterId = useTextEditingController(text: "");
final ctrlPassword = useTextEditingController(text: "");
final isLoading = useState(false);
final errorMessage = useState("");
final isSuccess = useState(false);
ref.listen(loginProvider, (prev, next) {
if (next is LoginStateLoading) {
isLoading.value = true;
} else if (next is LoginStateError) {
isLoading.value = false;
errorMessage.value = next.message;
Timer(const Duration(seconds: 3), () {
errorMessage.value = "";
});
} else if (next is LoginStateDone) {
isLoading.value = false;
isSuccess.value = true;
ref.read(currentPageProvider.state).update((state) => 0);
ref.read(currentUserProvider.notifier).state = next.model;
// print(next.model.model.doctorName);
// Navigator.of(context).pop();
// Navigator.of(context).pushNamedAndRemoveUntil(menuRoute,(route) => true,);
// Navigator.popAndPushNamed(context,menuRoute);
Navigator.of(context)
.pushNamedAndRemoveUntil(menuRoute, (route) => false);
}
});
return ListView(
children: [
Container(
width: Constant.getActualXPhone(context: context, x: 390),
height: Constant.getActualYPhone(context: context, y: 343),
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('images/header_tanpa_logo.png'),
fit: BoxFit.cover,
),
),
child: Column(
children: [
SizedBox(
height: Constant.getActualYPhone(context: context, y: 136),
),
Container(
width: Constant.getActualXPhone(context: context, x: 148),
height: Constant.getActualYPhone(context: context, y: 78),
decoration: BoxDecoration(
image: DecorationImage(
fit: BoxFit.fitHeight,
image: AssetImage('images/logo_pramita.png'),
),
),
),
],
),
),
SizedBox(
height: Constant.getActualYPhone(context: context, y: 43),
),
Container(
width: Constant.getActualXPhone(context: context, x: 391),
height: Constant.getActualYPhone(context: context, y: 454),
padding: EdgeInsets.only(
left: Constant.getActualXPhone(context: context, x: 32),
right: Constant.getActualXPhone(context: context, x: 32),
top: Constant.getActualYPhone(context: context, y: 20),
bottom: Constant.getActualYPhone(context: context, y: 20),
),
child: Column(
children: [
// form
SizedBox(
width: Constant.getActualXPhone(context: context, x: 180),
height: Constant.getActualYPhone(context: context, y: 29),
child: Align(
alignment: Alignment.center,
child: Text("LOGIN DOKTER",
style: Constant.titleH3_700(context: context)
.copyWith(color: Constant.subTitleBlack)),
),
),
SizedBox(
height: Constant.getActualYPhone(context: context, y: 4),
),
// notify error dari backend start
if (isLoading.value)
SizedBox(
width: Constant.getActualXPhone(context: context, x: 20),
height: Constant.getActualYPhone(context: context, y: 20),
child: CircularProgressIndicator(),
),
if (errorMessage.value != "")
Text(
"Peringatan : ${errorMessage.value}",
style: Constant.titleH7_700(context: context)
.copyWith(color: Constant.textRedProblemMaketing),
),
// notify error dari backend end
SizedBox(
height: Constant.getActualYPhone(context: context, y: 24),
),
// textfield marketing ID
SizedBox(
width: Constant.getActualXPhone(context: context, x: 320),
height: Constant.getActualYPhone(context: context, y: 50),
child: CustomTextField(
ctrl: ctrlDokterId,
isPassword: false,
hintText: "Doctor ID",
labelText: "Doctor ID",
isError: (errorMessage.value != "") ? true : false,
),
),
SizedBox(
height: Constant.getActualYPhone(context: context, y: 20),
),
// textfield username
SizedBox(
width: Constant.getActualXPhone(context: context, x: 320),
height: Constant.getActualYPhone(context: context, y: 50),
child: CustomTextField(
ctrl: ctrlUsername,
isPassword: false,
hintText: "Username",
labelText: "Username",
isError: (errorMessage.value != "") ? true : false,
),
),
SizedBox(
height: Constant.getActualYPhone(context: context, y: 20),
),
// textfield password
SizedBox(
width: Constant.getActualXPhone(context: context, x: 320),
height: Constant.getActualYPhone(context: context, y: 50),
child: CustomTextField(
ctrl: ctrlPassword,
isPassword: false,
obscureText: isPasswordObscured.value,
hintText: "Password",
labelText: "Password",
onToggle: () {
isPasswordObscured.value = !isPasswordObscured.value;
},
isError: (errorMessage.value != "") ? true : false,
),
),
SizedBox(
height: Constant.getActualYPhone(context: context, y: 40),
),
// button login
SizedBox(
width: Constant.getActualXPhone(context: context, x: 320),
height: Constant.getActualYPhone(context: context, y: 50),
child: ElevatedButton(
onPressed: (isSuccess.value == true)
? () {}
: () {
if (ctrlUsername.text.isEmpty ||
ctrlDokterId.text.isEmpty ||
ctrlPassword.text.isEmpty) {
isLoading.value = true;
errorMessage.value = 'Inputan harus diisi';
Timer(const Duration(seconds: 3), () {
isLoading.value = false;
errorMessage.value = "";
});
} else {
ref.read(loginProvider.notifier).login(
username: ctrlUsername.text,
dokterId: ctrlDokterId.text,
password: ctrlPassword.text);
}
},
style: ButtonStyle(
backgroundColor: MaterialStateColor.resolveWith((st) =>
(isSuccess.value == true)
? Constant.textGrey
: Constant.buttonLoginBackgroundColor),
shape: MaterialStateProperty.all<RoundedRectangleBorder>(
RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8.0),
side: BorderSide(color: Colors.red),
),
),
shadowColor: MaterialStateProperty.all(Color(0xffff48423d)),
elevation: MaterialStateProperty.all(4.0),
),
child: Align(
alignment: Alignment.center,
child: Text(
'LOGIN',
style: Constant.titleH3_700(context: context)
.copyWith(color: Constant.textLoginColor),
),
),
),
),
SizedBox(
height: Constant.getActualYPhone(context: context, y: 22),
),
// versi
Align(
alignment: Alignment.center,
child: Text(
'Versi ${Constant.version}',
style: Constant.titleH4Login(context: context)
.copyWith(color: Constant.textGrey),
),
),
// text problem login
// SizedBox(
// width: Constant.getActualXPhone(context: context, x: 121),
// height: Constant.getActualYPhone(context: context, y: 20),
// // color: Colors.brown,
// child: Align(
// alignment: Alignment.center,
// child: InkWell(
// onTap: () {
// Navigator.of(context).pushNamed(problemLoginRoute);
// },
// child: Text(
// 'Problem Login ? ',
// style: Constant.body1_400(context: context)
// .copyWith(color: Constant.textRedProblemMaketing),
// ),
// ),
// ),
// ),
],
),
),
],
);
}
}

View File

@@ -0,0 +1,375 @@
// ignore_for_file: prefer_const_constructors, use_full_hex_values_for_flutter_colors
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import '../../app/constant.dart';
import '../../app/route.dart';
import '../../provider/current_menu_provider.dart';
import '../../provider/current_user_provider.dart';
import 'custom_text_field.dart';
import 'login_provider.dart';
class BlockBodyV2 extends HookConsumerWidget {
const BlockBodyV2({
Key? key,
}) : super(key: key);
@override
Widget build(BuildContext context, WidgetRef ref) {
final isPasswordObscured = useState<bool>(true);
final ctrlUsername = useTextEditingController(text: "");
final ctrlDokterId = useTextEditingController(text: "");
final ctrlPassword = useTextEditingController(text: "");
final isLoading = useState(false);
final errorMessage = useState("");
final isSuccess = useState(false);
final focusNodeDokterID = useFocusNode();
final focusNodeDokterUsername = useFocusNode();
final focusNodeDokterPassword = useFocusNode();
final dokterIDhasFocus = useState(false);
final usernamehasFocus = useState(false);
final passwordhasFocus = useState(false);
focusNodeDokterID.addListener(() {
if (focusNodeDokterID.hasPrimaryFocus) {
dokterIDhasFocus.value = true;
usernamehasFocus.value = false;
passwordhasFocus.value = false;
} else {
dokterIDhasFocus.value = false;
}
});
focusNodeDokterUsername.addListener(() {
if (focusNodeDokterUsername.hasFocus) {
dokterIDhasFocus.value = false;
usernamehasFocus.value = true;
passwordhasFocus.value = false;
} else {
usernamehasFocus.value = false;
}
});
focusNodeDokterPassword.addListener(() {
if (focusNodeDokterPassword.hasFocus) {
dokterIDhasFocus.value = false;
usernamehasFocus.value = false;
passwordhasFocus.value = true;
} else {
passwordhasFocus.value = false;
}
});
ref.listen(loginProvider, (prev, next) {
if (next is LoginStateLoading) {
isLoading.value = true;
} else if (next is LoginStateError) {
isLoading.value = false;
errorMessage.value = next.message;
Timer(const Duration(seconds: 3), () {
errorMessage.value = "";
});
} else if (next is LoginStateDone) {
isLoading.value = false;
isSuccess.value = true;
ref.read(currentPageProvider.state).update((state) => 0);
ref.read(currentUserProvider.notifier).state = next.model;
// print(next.model.model.doctorName);
// Navigator.of(context).pop();
// Navigator.of(context).pushNamedAndRemoveUntil(menuRoute,(route) => true,);
// Navigator.popAndPushNamed(context,menuRoute);
Navigator.of(context)
.pushNamedAndRemoveUntil(menuRoute, (route) => false);
}
});
return ListView(
children: [
SizedBox(
height: Constant.getActualYPhone(context: context, y: 30),
),
Padding(
padding: EdgeInsets.only(
left: Constant.getActualXPhone(context: context, x: 40),
right: Constant.getActualXPhone(context: context, x: 40),
),
child: Container(
width: Constant.getActualXPhone(context: context, x: 283),
height: Constant.getActualYPhone(context: context, y: 100),
decoration: BoxDecoration(
// color: Colors.green,
image: DecorationImage(
fit: BoxFit.fitWidth,
// image: AssetImage('images/logo_pramita.png'),
image: AssetImage('images/logo_gabung_bg_png.png'),
),
),
),
),
SizedBox(
height: Constant.getActualYPhone(context: context, y: 60),
),
// form
Container(
width: Constant.getActualXPhone(context: context, x: 180),
height: Constant.getActualYPhone(context: context, y: 40),
// color: Colors.amber,
child: Align(
alignment: Alignment.center,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.max,
children: [
Text(
"LOGIN",
style: Constant.titleH3_700V2(context: context)
.copyWith(color: Constant.subTitleBlack),
),
Text(
" DOKTER",
style: Constant.titleH3_700V2(context: context).copyWith(
color: Color(0xffd70302),
),
),
],
),
),
),
SizedBox(
height: Constant.getActualYPhone(context: context, y: 20),
),
// notify error dari backend start
if (isLoading.value)
SizedBox(
width: Constant.getActualXPhone(context: context, x: 20),
height: Constant.getActualYPhone(context: context, y: 20),
child: Center(child: CircularProgressIndicator()),
),
if (errorMessage.value != "")
Center(
child: Text(
"Peringatan : ${errorMessage.value}",
style: Constant.titleH7_700(context: context)
.copyWith(color: Constant.textRedProblemMaketing),
),
),
// notify error dari backend end
SizedBox(
height: Constant.getActualYPhone(context: context, y: 50),
),
// textfield marketing ID
Padding(
padding: EdgeInsets.only(
left: Constant.getActualXPhone(context: context, x: 100),
right: Constant.getActualXPhone(context: context, x: 100),
),
child: Container(
width: Constant.getActualXPhone(context: context, x: 320),
height: Constant.getActualYPhone(context: context, y: 50),
// color: Colors.blue,
// decoration: BoxDecoration(
// // border: Border.all(color: Colors.black),
// color: Color(0xffee0606),
// borderRadius: BorderRadius.circular(30),
// ),
child: CustomTextFieldLogin(
// onTap: () {
// dokterIDhasFocus.value = true;
// },
// onEditingComplete: () {
// dokterIDhasFocus.value = false;
// },
onChange: (String x) {
// print(x);
if (x.isNotEmpty || ctrlDokterId.text.isNotEmpty) {
print('onchange');
focusNodeDokterID.requestFocus();
}
},
ctrl: ctrlDokterId,
focusNode: focusNodeDokterID,
hasFocus: dokterIDhasFocus.value,
isPassword: false,
hintText: "DOKTER ID",
labelText: "DOKTER ID",
isError: (errorMessage.value != "") ? true : false,
),
),
),
SizedBox(
height: Constant.getActualYPhone(context: context, y: 40),
),
// textfield username
Padding(
padding: EdgeInsets.only(
left: Constant.getActualXPhone(context: context, x: 100),
right: Constant.getActualXPhone(context: context, x: 100),
),
child: Container(
width: Constant.getActualXPhone(context: context, x: 320),
height: Constant.getActualYPhone(context: context, y: 50),
// color: Colors.blue,
// decoration: BoxDecoration(
// // border: Border.all(color: Colors.black),
// color: Color(0xffee0606),
// borderRadius: BorderRadius.circular(30),
// ),
child: CustomTextFieldLogin(
// onTap: () {
// if (ctrlUsername.text.isNotEmpty) {
// focusNodeDokterUsername.requestFocus();
// }
// },
onChange: (String x) {
// print(x);
if (x.isNotEmpty || ctrlUsername.text.isNotEmpty) {
focusNodeDokterUsername.requestFocus();
}
},
ctrl: ctrlUsername,
focusNode: focusNodeDokterUsername,
hasFocus: usernamehasFocus.value,
isPassword: false,
hintText: "USERNAME",
labelText: "USERNAME",
isError: (errorMessage.value != "") ? true : false,
),
),
),
SizedBox(
height: Constant.getActualYPhone(context: context, y: 40),
),
// textfield password
Padding(
padding: EdgeInsets.only(
left: Constant.getActualXPhone(context: context, x: 100),
right: Constant.getActualXPhone(context: context, x: 100),
),
child: Container(
width: Constant.getActualXPhone(context: context, x: 320),
height: Constant.getActualYPhone(context: context, y: 50),
// color: Colors.blue,
// decoration: BoxDecoration(
// // border: Border.all(color: Colors.black),
// color: Color(0xffee0606),
// borderRadius: BorderRadius.circular(30),
// ),
child: CustomTextFieldLogin(
// onTap: () {
// if (ctrlPassword.text.isNotEmpty) {
// focusNodeDokterPassword.requestFocus();
// }
// },
onChange: (String x) {
// print(x);
if (x.isNotEmpty || ctrlPassword.text.isNotEmpty) {
focusNodeDokterPassword.requestFocus();
}
},
ctrl: ctrlPassword,
focusNode: focusNodeDokterPassword,
hasFocus: passwordhasFocus.value,
isPassword: false,
obscureText: isPasswordObscured.value,
hintText: "PASSWORD",
labelText: "PASSWORD",
onToggle: () {
isPasswordObscured.value = !isPasswordObscured.value;
},
isError: (errorMessage.value != "") ? true : false,
),
),
),
SizedBox(
height: Constant.getActualYPhone(context: context, y: 40),
),
// button login
Padding(
padding: EdgeInsets.only(
left: Constant.getActualXPhone(context: context, x: 100),
right: Constant.getActualXPhone(context: context, x: 100),
),
child: SizedBox(
width: Constant.getActualXPhone(context: context, x: 320),
height: Constant.getActualYPhone(context: context, y: 50),
child: ElevatedButton(
onPressed: (isSuccess.value == true)
? () {}
: () {
if (ctrlUsername.text.isEmpty ||
ctrlDokterId.text.isEmpty ||
ctrlPassword.text.isEmpty) {
isLoading.value = true;
errorMessage.value = 'Inputan harus diisi';
Timer(const Duration(seconds: 3), () {
isLoading.value = false;
errorMessage.value = "";
});
} else {
ref.read(loginProvider.notifier).login(
username: ctrlUsername.text,
dokterId: ctrlDokterId.text,
password: ctrlPassword.text);
}
},
style: ButtonStyle(
backgroundColor: MaterialStateColor.resolveWith((st) =>
(isSuccess.value == true)
? Constant.textGrey
: Constant.buttonRedBackgroundColor),
shape: MaterialStateProperty.all<RoundedRectangleBorder>(
RoundedRectangleBorder(
borderRadius: BorderRadius.circular(30),
side: BorderSide(color: Colors.red),
),
),
shadowColor: MaterialStateProperty.all(Color(0xffff48423d)),
elevation: MaterialStateProperty.all(4.0),
),
child: Align(
alignment: Alignment.center,
child: Text(
'SIGN IN',
style: Constant.titleH3_700(context: context)
.copyWith(color: Constant.textLoginColor),
),
),
),
),
),
SizedBox(
height: Constant.getActualYPhone(context: context, y: 22),
),
// versi
Align(
alignment: Alignment.center,
child: Text(
'Versi ${Constant.version}',
style: Constant.titleH4Login(context: context)
.copyWith(color: Constant.textGrey),
),
),
],
);
}
}

View File

@@ -0,0 +1,19 @@
import 'package:flutter/material.dart';
import '../../app/constant.dart';
class BlokHeader extends StatelessWidget {
const BlokHeader({
Key? key,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Image.asset(
'images/Background.png',
fit: BoxFit.fill,
width: Constant.getActualXPhone(context: context, x: 390),
height: double.infinity,
);
}
}

View File

@@ -0,0 +1,290 @@
import 'package:flutter/material.dart';
import '../../app/constant.dart';
// login
class CustomTextFieldLogin extends StatelessWidget {
final String hintText;
final String labelText;
final bool isPassword;
final bool obscureText;
final bool isMaxLine;
final void Function()? onToggle;
final TextEditingController? ctrl;
final void Function(String)? onChange;
final void Function(String)? onSubmitted;
final void Function()? onTap;
final void Function()? onEditingComplete;
final FocusNode? focusNode;
final bool isPrefix;
final bool isError;
final bool isTextArea;
final bool isReadOnly;
final bool hasFocus;
const CustomTextFieldLogin({
Key? key,
required this.hintText,
required this.labelText,
this.isPassword = false,
this.isMaxLine = false,
this.onToggle,
this.obscureText = false,
this.ctrl,
this.onChange,
this.onSubmitted,
this.focusNode,
this.isPrefix = false,
this.isTextArea = false,
this.isError = false,
this.isReadOnly = false,
this.hasFocus = false,
this.onTap,
this.onEditingComplete
}) : super(key: key);
@override
Widget build(BuildContext context) {
return TextField(
autofocus: true,
showCursor: (hasFocus) ? true : false,
readOnly: isReadOnly,
controller: ctrl,
enableInteractiveSelection: false,
style:
Constant.titleH4Login(context: context).copyWith(color: Colors.white),
obscureText: obscureText,
onChanged: onChange,
onSubmitted: onSubmitted,
onTap: onTap,
onEditingComplete: onEditingComplete,
focusNode: focusNode,
maxLines: (isTextArea) ? 4 : 1,
cursorColor: Colors.white,
decoration: InputDecoration(
fillColor: (hasFocus) ? Color(0xffff6868) : Color(0xffd90504),
filled: true,
focusedBorder: OutlineInputBorder(
borderSide:
BorderSide(color: Constant.buttonLoginBackgroundColor, width: 2),
borderRadius: BorderRadius.circular(30),
),
enabledBorder: (isError == true)
? OutlineInputBorder(
// ignore: prefer_const_constructors
borderRadius: BorderRadius.all(Radius.circular(30)),
borderSide: BorderSide(
color: Constant.textRedProblemMaketing,
width: 1,
),
)
: OutlineInputBorder(
// ignore: prefer_const_constructors
borderRadius: BorderRadius.all(Radius.circular(30)),
borderSide: BorderSide(
color: Constant.buttonLoginBackgroundColor,
width: 2,
),
),
// hintStyle: Constant.body1_400(context: context)
// .copyWith(color: Constant.textBlack),
// labelStyle: Constant.body3_400(context: context),
hintStyle:
Constant.body3_400(context: context).copyWith(color: Colors.white),
labelStyle: Constant.body3_400(context: context),
// labelText: labelText,
hintText: hintText,
alignLabelWithHint: true,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(30),
),
prefixIcon: isPrefix ? const Icon(Icons.search) : null,
prefixStyle: isPrefix ? Constant.titleH4Login(context: context) : null,
// suffixIcon: isPassword
// ? IconButton(
// alignment: Alignment.centerRight,
// onPressed: onToggle,
// icon: const Icon(Icons.remove_red_eye),
// iconSize: Constant.getActualYPhone(context: context, y: 24),
// )
// : null,
),
);
}
}
// selain login
class CustomTextField extends StatelessWidget {
final String hintText;
final String labelText;
final bool isPassword;
final bool obscureText;
final bool isMaxLine;
final void Function()? onToggle;
final TextEditingController? ctrl;
final void Function(String)? onChange;
final void Function(String)? onSubmitted;
final FocusNode? focusNode;
final bool isPrefix;
final bool isError;
final bool isTextArea;
final bool isReadOnly;
const CustomTextField(
{Key? key,
required this.hintText,
required this.labelText,
this.isPassword = false,
this.isMaxLine = false,
this.onToggle,
this.obscureText = false,
this.ctrl,
this.onChange,
this.onSubmitted,
this.focusNode,
this.isPrefix = false,
this.isTextArea = false,
this.isError = false,
this.isReadOnly = false})
: super(key: key);
@override
Widget build(BuildContext context) {
return TextField(
readOnly: isReadOnly,
controller: ctrl,
style: Constant.titleH4Login(context: context),
obscureText: obscureText,
onChanged: onChange,
onSubmitted: onSubmitted,
focusNode: focusNode,
maxLines: (isTextArea) ? 4 : 1,
decoration: InputDecoration(
// focusedBorder: OutlineInputBorder(
// borderSide: BorderSide(color: Constant.textGrey, width: 1),
// borderRadius: BorderRadius.circular(8.0),
// ),
enabledBorder: (isError == true)
? OutlineInputBorder(
// ignore: prefer_const_constructors
borderRadius: BorderRadius.all(Radius.circular(8)),
borderSide: BorderSide(
color: Constant.textRedProblemMaketing,
width: 1,
),
)
: null,
// hintStyle: Constant.body1_400(context: context)
// .copyWith(color: Constant.textBlack),
// labelStyle: Constant.body3_400(context: context),
hintStyle: Constant.body3_400(context: context),
labelStyle: Constant.body3_400(context: context),
labelText: labelText,
hintText: hintText,
alignLabelWithHint: true,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
),
prefixIcon: isPrefix ? const Icon(Icons.search) : null,
prefixStyle: isPrefix ? Constant.titleH4Login(context: context) : null,
// suffixIcon: isPassword
// ? IconButton(
// alignment: Alignment.centerRight,
// onPressed: onToggle,
// icon: const Icon(Icons.remove_red_eye),
// iconSize: Constant.getActualYPhone(context: context, y: 24),
// )
// : null,
),
);
}
}
// untuk inputan selain login
class CustomTextFieldV2 extends StatelessWidget {
final String hintText;
final String labelText;
final bool isPassword;
final bool obscureText;
final bool isMaxLine;
final void Function()? onToggle;
final TextEditingController? ctrl;
final void Function(String)? onChange;
final void Function(String)? onSubmitted;
final FocusNode? focusNode;
final bool isPrefix;
final InkWell? suffixIcon;
final bool isError;
final bool isTextArea;
const CustomTextFieldV2(
{Key? key,
required this.hintText,
required this.labelText,
this.isPassword = false,
this.isMaxLine = false,
this.onToggle,
this.obscureText = false,
this.ctrl,
this.onChange,
this.onSubmitted,
this.focusNode,
this.isPrefix = false,
this.isTextArea = false,
this.isError = false,
this.suffixIcon})
: super(key: key);
@override
Widget build(BuildContext context) {
return TextField(
controller: ctrl,
style: Constant.titleH4Login(context: context),
obscureText: obscureText,
onChanged: onChange,
onSubmitted: onSubmitted,
focusNode: focusNode,
maxLines: (isTextArea) ? 4 : 1,
decoration: InputDecoration(
// focusedBorder: OutlineInputBorder(
// borderSide: BorderSide(color: Constant.textGrey, width: 1),
// borderRadius: BorderRadius.circular(8.0),
// ),
enabledBorder: (isError == true)
? OutlineInputBorder(
// ignore: prefer_const_constructors
borderRadius: BorderRadius.all(Radius.circular(8)),
borderSide: BorderSide(
color: Constant.textRedProblemMaketing,
width: 1,
),
)
: null,
hintStyle: Constant.body3_400(context: context),
labelStyle: Constant.body3_400(context: context),
labelText: labelText,
hintText: hintText,
alignLabelWithHint: true,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
),
prefixIcon: isPrefix ? const Icon(Icons.search) : null,
prefixStyle:
isPrefix ? Constant.titleH4Login(context: context) : null,
suffixIcon: suffixIcon
// suffixIcon: isPassword
// ? IconButton(
// alignment: Alignment.centerRight,
// onPressed: onToggle,
// icon: const Icon(Icons.remove_red_eye),
// iconSize: Constant.getActualYPhone(context: context, y: 24),
// )
// : null,
),
);
}
}

View File

@@ -0,0 +1,83 @@
import 'dart:convert';
import 'package:equatable/equatable.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:shared_preferences/shared_preferences.dart';
import '../../app/constant.dart';
import '../../model/auth_model.dart';
import '../../provider/current_user_provider.dart';
import '../../provider/dio_provider.dart';
import '../../repository/auth_repository.dart';
import '../../repository/base_repository.dart';
// 3. state provider
final loginProvider = StateNotifierProvider<LoginNotifier, LoginState>(
(ref) => LoginNotifier(ref: ref));
// 2. notifier
class LoginNotifier extends StateNotifier<LoginState> {
final Ref ref;
LoginNotifier({required this.ref}) : super(LoginStateInit());
void login({
required String username,
required String dokterId,
required String password,
}) async {
try {
state = LoginStateLoading();
final resp = await AuthRepository(dio: ref.read(dioProvider))
.login(username: username, dokterId: dokterId, password: password);
// print(resp);
state = LoginStateDone(model: resp);
//Simpan ke token
final shared = await SharedPreferences.getInstance();
final token = jsonEncode({
"date": DateTime.now().toString(),
"model": resp.model,
"token": resp.token
});
await shared.setString(Constant.bearerName, token);
ref.read(currentUserProvider.notifier).state = resp;
// print(shared.getString(Constant.bearerName));
} catch (e) {
if (e is BaseRepositoryException) {
state = LoginStateError(message: e.message);
} else {
state = LoginStateError(message: e.toString());
}
}
}
}
// 1. state
abstract class LoginState extends Equatable {
final DateTime date;
const LoginState(this.date);
@override
List<Object?> get props => [date];
}
class LoginStateInit extends LoginState {
LoginStateInit() : super(DateTime.now());
}
class LoginStateLoading extends LoginState {
LoginStateLoading() : super(DateTime.now());
}
class LoginStateError extends LoginState {
final String message;
LoginStateError({
required this.message,
}) : super(DateTime.now());
}
class LoginStateDone extends LoginState {
final AuthModel model;
LoginStateDone({
required this.model,
}) : super(DateTime.now());
}

View File

@@ -0,0 +1,79 @@
// ignore_for_file: use_build_context_synchronously, prefer_const_constructors
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:shared_preferences/shared_preferences.dart';
import '../../app/constant.dart';
import '../../app/route.dart';
import '../../model/auth_model.dart';
import '../../provider/current_menu_provider.dart';
import '../../provider/current_user_provider.dart';
import 'block_body.dart';
import 'block_bodyv2.dart';
class LoginScreen extends HookConsumerWidget {
const LoginScreen({Key? key}) : super(key: key);
@override
Widget build(BuildContext context, WidgetRef ref) {
useEffect(() {
WidgetsBinding.instance.addPostFrameCallback((timeStamp) async {
final shared = await SharedPreferences.getInstance();
final bearerString = shared.get(Constant.bearerName).toString();
final xmodel = jsonDecode(bearerString);
if (xmodel == null) return;
final authModel = AuthModel(
token: xmodel["token"],
model: AuthDoctorModel(
M_UserM_DoctorID: xmodel["model"]["M_UserM_DoctorID"],
M_UserUsername: xmodel["model"]["M_UserUsername"],
M_UserM_DoctorCode: xmodel["model"]["M_UserM_DoctorCode"],
M_UserM_MouID: xmodel["model"]["M_UserM_MouID"] ?? "",
M_UserID: xmodel["model"]["M_UserID"]),
);
ref.read(currentUserProvider.notifier).state = authModel;
ref.read(currentPageProvider.state).update((state) => 0);
Navigator.of(context).pushNamedAndRemoveUntil(
menuRoute,
(route) => false,
);
});
return () {};
}, []);
return GestureDetector(
// buat dismiss keyboard
onTap: () => FocusManager.instance.primaryFocus?.unfocus(),
child: Scaffold(
resizeToAvoidBottomInset: true,
backgroundColor: Constant.backgroundColor,
body: SafeArea(
child: Center(
child: Container(
width: Constant.getActualXPhone(context: context, x: 390),
height: Constant.getActualYPhone(context: context, y: 844),
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [
Color(0xffdadae6),
Color(0xfff6f7fb),
],
begin: Alignment.centerLeft,
end: Alignment.centerRight,
),
),
// child: BlockBody(),
child: BlockBodyV2(),
),
),
),
),
);
}
}

View File

@@ -0,0 +1,64 @@
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import '../../app/constant.dart';
import '../../app/route.dart';
import '../../provider/current_user_provider.dart';
class SplashScreen extends HookConsumerWidget {
const SplashScreen({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
// useEffect(() {
// WidgetsBinding.instance.addPostFrameCallback((timeStamp) async {
// final doctorID =
// ref.read(currentUserProvider)?.model.M_UserM_DoctorCode ?? "0";
// // print(doctorID);
// if (doctorID == "0") {
// //not login
// Navigator.of(context)
// .pushNamedAndRemoveUntil(loginRoute, (route) => false);
// return;
// } else {
// Navigator.of(context)
// .pushNamedAndRemoveUntil(menuRoute, (route) => false);
// }
// });
// return () {};
// }, []);
// setelah 3 detik redirect ke login route
Timer(const Duration(seconds: 3), () {
Navigator.of(context).pushNamedAndRemoveUntil(
loginRoute,
(route) => false,
);
});
return Scaffold(
// appBar: AppBar(
// backgroundColor: Constant.backgroundColor,
// elevation: 0,
// ),
backgroundColor: Constant.backgroundColor,
body: SafeArea(
child: Container(
width: Constant.getActualXPhone(context: context, x: 390),
height: Constant.getActualYPhone(context: context, y: 844),
child: Image.asset(
"images/splashscreen.png",
fit: BoxFit.cover,
// scale: 1,
),
// color: Colors.green,
),
),
);
}
}