Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
Menu
Open sidebar
Sai Srinivas
GEN_ERP_2025
Commits
dc88a3f9
Commit
dc88a3f9
authored
Oct 08, 2025
by
Sai Srinivas
Browse files
gen erp 08-10
parent
d2c9404a
Changes
42
Show whitespace changes
Inline
Side-by-side
lib/Notifiers/splashVersionNotifier.dart
View file @
dc88a3f9
import
'dart:io'
;
import
'dart:math'
;
import
'package:flutter/foundation.dart'
;
import
'package:flutter/material.dart'
;
import
'package:generp/Models/VersionsResponse.dart'
;
import
'package:generp/Notifiers/HomeScreenNotifier.dart'
;
import
'package:generp/Notifiers/loginNotifier.dart'
;
import
'package:generp/Utils/SharedpreferencesService.dart'
;
import
'package:generp/screens/HomeScreen.dart'
;
...
...
@@ -55,7 +54,7 @@ class SplashVersionNotifier extends ChangeNotifier {
if
(
data
!=
null
)
{
if
(
kDebugMode
)
{
print
(
"Current Build:
$currentBuild
"
);
print
(
"Server Response:
$data
"
);
print
(
"Server Response:
$
{
data
.latestVersionCode}
"
);
}
if
(
Platform
.
isAndroid
&&
currentBuild
<
(
data
.
latestVersionCode
??
0
))
{
...
...
lib/main.dart
View file @
dc88a3f9
import
'dart:convert'
;
import
'dart:io'
;
import
'package:firebase_core/firebase_core.dart'
;
...
...
@@ -10,56 +11,138 @@ import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import
'package:flutter_ringtone_player/flutter_ringtone_player.dart'
;
import
'package:generp/Models/hrmModels/leaveApplicationLIstResponse.dart'
;
import
'package:generp/Utils/app_colors.dart'
;
import
'package:generp/screens/AttendanceScreen.dart'
;
import
'package:generp/screens/crm/LeadDetailsByMode.dart'
;
import
'package:generp/screens/crm/ProspectListByMode.dart'
;
import
'package:generp/screens/crm/crmDashboard.dart'
;
import
'package:generp/screens/hrm/Attendancelist.dart'
;
import
'package:generp/screens/hrm/OrganizationStructureScreen.dart'
;
import
'package:generp/screens/hrm/TourExpensesListScreen.dart'
;
import
'Notifiers/hrmProvider/advanceProvider.dart'
;
import
'screens/notifierExports.dart'
;
import
'package:generp/Utils/SharedpreferencesService.dart'
;
import
'package:generp/screens/splash.dart'
;
import
'package:provider/provider.dart'
;
import
'Utils/commonWidgets.dart'
;
// Navigator Key for global navigation
final
GlobalKey
<
NavigatorState
>
navigatorKey
=
GlobalKey
<
NavigatorState
>();
// Notification Channel
const
AndroidNotificationChannel
channel
=
AndroidNotificationChannel
(
'generp_channel'
,
// id
'generp_channel'
,
'generp_channel_name'
,
importance:
Importance
.
max
,
playSound:
fals
e
,
playSound:
tru
e
,
);
final
FlutterLocalNotificationsPlugin
flutterLocalNotificationsPlugin
=
FlutterLocalNotificationsPlugin
();
FlutterLocalNotificationsPlugin
();
Future
<
void
>
_firebaseMessagingBackgroundHandler
(
RemoteMessage
message
)
async
{
await
Firebase
.
initializeApp
();
String
type
=
message
.
data
[
'type'
]
??
''
;
debugPrint
(
"📩 Background notification received:
${message.data}
"
);
}
void
handleNotificationTap
(
Map
<
String
,
dynamic
>
data
)
{
debugPrint
(
"👉 Handling notification tap:
$data
"
);
if
(
type
==
'offline_reminder'
)
{
FlutterRingtonePlayer
().
play
(
// fromAsset: "assets/offline_reminder.mp3",
ios:
IosSounds
.
glass
,
// Specify the iOS sound
try
{
String
type
=
data
[
'type'
]
??
''
;
String
?
rollId
=
data
[
'RoleID'
]
??
data
[
'rollId'
];
String
?
notificationId
=
data
[
'notification_id'
]
??
data
[
'notificationId'
];
String
?
url
=
data
[
'url'
];
String
?
mode
=
data
[
'Parameter'
];
debugPrint
(
"👉 Handling notification tap:
$mode
"
);
if
(
type
.
toLowerCase
()
==
"app"
)
{
// 🔥 Navigation based on RoleID
switch
(
rollId
)
{
case
"1"
:
navigatorKey
.
currentState
?.
pushNamed
(
'/crm_lead_list'
);
break
;
case
"4"
:
navigatorKey
.
currentState
?.
pushNamed
(
'/crm_prospect_list'
);
break
;
case
"5"
:
navigatorKey
.
currentState
?.
pushNamed
(
'/crm_prospect_details'
,
arguments:
{
"id"
:
notificationId
},
);
}
else
if
(
type
==
'normal'
)
{
FlutterRingtonePlayer
().
play
(
// fromAsset: "assets/notification_sound.mp3",
ios:
IosSounds
.
glass
,
// Specify the iOS sound
break
;
case
"6"
:
navigatorKey
.
currentState
?.
pushNamed
(
'/crm_lead_details'
,
arguments:
{
"id"
:
notificationId
},
);
}
else
if
(
type
==
'web_erp_notification'
)
{
FlutterRingtonePlayer
().
play
(
// fromAsset: "assets/notification_sound.mp3",
ios:
IosSounds
.
glass
,
// Specify the iOS sound
break
;
case
"7"
:
navigatorKey
.
currentState
?.
pushNamed
(
'/dashboard'
);
break
;
case
"8"
:
navigatorKey
.
currentState
?.
pushNamed
(
'/crm_new_customer_new_lead_register'
);
break
;
case
"10"
:
navigatorKey
.
currentState
?.
pushNamed
(
'/crm_prospect_list_team'
);
break
;
case
"11"
:
navigatorKey
.
currentState
?.
pushNamed
(
'/crm_prospect_list_admin'
);
break
;
case
"15"
:
navigatorKey
.
currentState
?.
pushNamed
(
'/finance_list_employee'
);
break
;
case
"16"
:
navigatorKey
.
currentState
?.
pushNamed
(
'/finance_list_admin'
);
break
;
case
"17"
:
navigatorKey
.
currentState
?.
pushNamed
(
'/dispatch_list_executive'
);
break
;
case
"312"
:
navigatorKey
.
currentState
?.
pushNamed
(
'/tour_bill_list'
);
break
;
case
"601"
:
navigatorKey
.
currentState
?.
pushNamed
(
'/manual_attendance_request_list'
);
break
;
default
:
navigatorKey
.
currentState
?.
pushNamed
(
'/home'
);
// fallback
}
}
else
if
(
type
.
toLowerCase
()
==
"web"
&&
url
!=
null
&&
url
.
isNotEmpty
)
{
// Open in WebView or browser
navigatorKey
.
currentState
?.
pushNamed
(
'/webview'
,
arguments:
{
"url"
:
url
},
);
}
else
{
FlutterRingtonePlayer
().
play
(
// fromAsset: "assets/notification_sound.mp3",
// will be the sound on Android
ios:
IosSounds
.
glass
,
// will be the sound on iOS
);
// fallback
navigatorKey
.
currentState
?.
pushNamed
(
'/home'
);
}
if
(
kDebugMod
e
)
{
print
(
'A Background message just showed up:
${message.messageId}
'
);
}
catch
(
e
)
{
debugPrint
(
"❌ Error handling notification tap:
$e
"
);
}
}
// FlutterLocalNotificationsPlugin cannot auto-detect foreground taps
void
showInAppNotification
(
BuildContext
context
,
Map
<
String
,
dynamic
>
data
)
{
final
snackBar
=
SnackBar
(
content:
Text
(
data
[
'type'
]
??
"New Notification"
),
action:
SnackBarAction
(
label:
'Open'
,
onPressed:
()
{
debugPrint
(
"👉 Foreground notification tapped:
$data
"
);
handleNotificationTap
(
data
);
},
),
);
ScaffoldMessenger
.
of
(
context
).
showSnackBar
(
snackBar
);
}
void
main
(
)
async
{
WidgetsFlutterBinding
.
ensureInitialized
();
// Firebase init
if
(
Platform
.
isAndroid
)
{
await
Firebase
.
initializeApp
(
options:
FirebaseOptions
(
...
...
@@ -72,60 +155,147 @@ void main() async {
}
else
if
(
Platform
.
isIOS
)
{
await
Firebase
.
initializeApp
();
}
if
(
kDebugMode
)
{
if
(
Firebase
.
apps
.
isNotEmpty
)
{
print
(
"Firebase is initialized"
);
}
else
{
print
(
"Firebase is not initialized"
);
// 🔔 Local Notification Init
const
AndroidInitializationSettings
initSettingsAndroid
=
AndroidInitializationSettings
(
'@mipmap/ic_launcher'
);
const
DarwinInitializationSettings
initSettingsIOS
=
DarwinInitializationSettings
();
const
InitializationSettings
initializationSettings
=
InitializationSettings
(
android:
initSettingsAndroid
,
iOS:
initSettingsIOS
,
);
flutterLocalNotificationsPlugin
.
initialize
(
initializationSettings
,
onDidReceiveNotificationResponse:
(
NotificationResponse
notificationResponse
)
async
{
if
(
notificationResponse
.
payload
!=
null
)
{
handleNotificationTap
(
jsonDecode
(
notificationResponse
.
payload
!));
debugPrint
(
"📩 Notification clicked:
$notificationResponse
"
);
}
}
);
// Firebase Messaging
FirebaseMessaging
.
onBackgroundMessage
(
_firebaseMessagingBackgroundHandler
);
FirebaseMessaging
messaging
=
FirebaseMessaging
.
instance
;
await
messaging
.
requestPermission
(
alert:
true
,
badge:
true
,
sound:
true
);
NotificationSettings
settings
=
await
messaging
.
requestPermission
(
alert:
true
,
announcement:
true
,
badge:
true
,
carPlay:
false
,
criticalAlert:
false
,
provisional:
false
,
sound:
false
,
);
// Foreground notification
FirebaseMessaging
.
onMessage
.
listen
((
RemoteMessage
message
)
{
RemoteNotification
?
notification
=
message
.
notification
;
AndroidNotification
?
android
=
message
.
notification
?.
android
;
print
(
"msg"
);
String
type
=
message
.
data
[
'type'
]
??
''
;
if
(
type
==
'offline_reminder'
)
{
FlutterRingtonePlayer
().
play
(
fromAsset:
"assets/offline_reminder.mp3"
,
ios:
IosSounds
.
glass
,
// Specify the iOS sound
);
}
else
if
(
type
==
'normal'
)
{
FlutterRingtonePlayer
().
play
(
fromAsset:
"assets/notification_sound.mp3"
,
ios:
IosSounds
.
glass
,
// Specify the iOS sound
);
}
else
if
(
type
==
'web_erp_notification'
)
{
FlutterRingtonePlayer
().
play
(
fromAsset:
"assets/notification_sound.mp3"
,
ios:
IosSounds
.
glass
,
// Specify the iOS sound
);
}
else
{
FlutterRingtonePlayer
().
play
(
fromAsset:
"assets/notification_sound.mp3"
,
// will be the sound on Android
ios:
IosSounds
.
glass
,
// will be the sound on iOS
final
notification
=
message
.
notification
;
final
android
=
message
.
notification
?.
android
;
debugPrint
(
"😊 Foreground msg received:
${message.data}
"
);
if
(
notification
!=
null
&&
android
!=
null
)
{
// flutterLocalNotificationsPlugin.show(
// notification.hashCode,
// notification.title,
// notification.body,
// NotificationDetails(
// android: AndroidNotificationDetails(
// channel.id,
// channel.name,
// importance: Importance.max,
// priority: Priority.high,
// icon: '@mipmap/ic_launcher',
// ),
// ),
// payload: jsonEncode({
// "type": message.data['type'],
// "rollId": message.data['RoleID'],
// "notificationId": message.data['notification_id'],
// }),
// );
}
// ⚡ Foreground tap alternative:
// Show an in-app banner or SnackBar with a tap action
final
context
=
navigatorKey
.
currentContext
;
if
(
context
!=
null
)
{
// Add haptic feedback
HapticFeedback
.
mediumImpact
();
ScaffoldMessenger
.
of
(
context
).
showSnackBar
(
SnackBar
(
content:
Row
(
children:
[
SizedBox
(
child:
Image
.
asset
(
"assets/images/ic_splash.jpg"
,
height:
30
,
width:
30
,
),
),
SizedBox
(
width:
8
),
Expanded
(
child:
Column
(
crossAxisAlignment:
CrossAxisAlignment
.
start
,
mainAxisSize:
MainAxisSize
.
min
,
children:
[
Text
(
notification
?.
title
??
"New Notification"
,
style:
TextStyle
(
fontSize:
14
,
color:
AppColors
.
app_blue
,
fontFamily:
"JakartaMedium"
,
),
),
if
(
notification
?.
body
!=
null
)
SizedBox
(
height:
2
),
if
(
notification
?.
body
!=
null
)
Text
(
notification
!.
body
!,
style:
TextStyle
(
fontSize:
12
,
color:
AppColors
.
semi_black
,
fontFamily:
"JakartaMedium"
,
),
),
],
),
),
],
),
action:
SnackBarAction
(
label:
"Open"
,
textColor:
AppColors
.
app_blue
,
onPressed:
()
{
// Add haptic feedback for button press
HapticFeedback
.
lightImpact
();
debugPrint
(
"👉 Foreground notification tapped:
${message.data}
"
);
// Use the same payload structure as local notifications
handleNotificationTap
({
"type"
:
message
.
data
[
'type'
],
"rollId"
:
message
.
data
[
'RoleID'
],
"notificationId"
:
message
.
data
[
'notification_id'
],
});
},
),
backgroundColor:
AppColors
.
white
,
behavior:
SnackBarBehavior
.
floating
,
elevation:
6
,
shape:
RoundedRectangleBorder
(
borderRadius:
BorderRadius
.
circular
(
8
),
),
margin:
const
EdgeInsets
.
all
(
16
),
duration:
const
Duration
(
seconds:
4
),
),
);
}
});
FirebaseMessaging
.
onBackgroundMessage
(
_firebaseMessagingBackgroundHandler
);
await
flutterLocalNotificationsPlugin
.
resolvePlatformSpecificImplementation
<
AndroidFlutterLocalNotificationsPlugin
>()
AndroidFlutterLocalNotificationsPlugin
>()
?.
createNotificationChannel
(
channel
);
await
FirebaseMessaging
.
instance
.
setForegroundNotificationPresentationOptions
(
...
...
@@ -134,13 +304,27 @@ void main() async {
sound:
true
,
);
await
FirebaseMessaging
.
instance
.
getToken
().
then
((
value
)
{
String
?
token
=
value
;
FirebaseMessaging
.
onMessageOpenedApp
.
listen
((
RemoteMessage
message
)
{
String
type
=
message
.
data
[
'type'
]
??
''
;
String
redirectUrl
=
message
.
data
[
'redirect_url'
]
??
''
;
handleNotificationTap
(
message
.
data
);
// Navigator.push(
// context,
// MaterialPageRoute(builder: (context) => Dashboard()),
// );
if
(
kDebugMode
)
{
//
print(
"fbstoken:{$token}"
);
print
(
'A new onMessageOpenedApp event was published!'
);
}
});
SharedpreferencesService
().
saveString
(
"fbstoken"
,
token
!);
// Save FCM Token
await
FirebaseMessaging
.
instance
.
getToken
().
then
((
value
)
{
if
(
value
!=
null
)
{
SharedpreferencesService
().
saveString
(
"fbstoken"
,
value
);
debugPrint
(
"🔑 FCM Token:
$value
"
);
}
});
runApp
(
const
MyApp
());
...
...
@@ -153,19 +337,19 @@ class MyApp extends StatelessWidget {
@override
Widget
build
(
BuildContext
context
)
{
// SystemChrome.setApplicationSwitcherDescription(ApplicationSwitcherDescription());
SystemChrome
.
setEnabledSystemUIMode
(
SystemUiMode
.
edgeToEdge
);
FirebaseMessaging
.
onMessageOpenedApp
.
listen
((
RemoteMessage
message
)
{
String
type
=
message
.
data
[
'type'
]
??
''
;
String
redirectUrl
=
message
.
data
[
'redirect_url'
]
??
''
;
// Navigator.push(
// context,
// MaterialPageRoute(builder: (context) => Dashboard()),
// );
if
(
kDebugMode
)
{
print
(
'A new onMessageOpenedApp event was published!'
);
}
});
//
SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge);
//
FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) {
//
String type = message.data['type'] ?? '';
//
String redirectUrl = message.data['redirect_url'] ?? '';
//
//
// Navigator.push(
//
// context,
//
// MaterialPageRoute(builder: (context) => Dashboard()),
//
// );
//
if (kDebugMode) {
//
print('A new onMessageOpenedApp event was published!');
//
}
//
});
return
MultiProvider
(
providers:
[
ChangeNotifierProvider
(
create:
(
_
)
=>
SplashVersionNotifier
()),
...
...
@@ -226,9 +410,7 @@ class MyApp extends StatelessWidget {
ChangeNotifierProvider
(
create:
(
_
)
=>
Dispatchorderprovider
()),
ChangeNotifierProvider
(
create:
(
_
)
=>
followUpUpdateProvider
()),
ChangeNotifierProvider
(
create:
(
_
)
=>
Appointmentcalendarprovider
()),
ChangeNotifierProvider
(
create:
(
_
)
=>
Addnewleadsandprospectsprovider
(),
),
ChangeNotifierProvider
(
create:
(
_
)
=>
Addnewleadsandprospectsprovider
()),
ChangeNotifierProvider
(
create:
(
_
)
=>
HrmAccessiblePagesProvider
()),
ChangeNotifierProvider
(
create:
(
_
)
=>
Attendancelistprovider
()),
ChangeNotifierProvider
(
create:
(
_
)
=>
AttendanceDetailsProvider
()),
...
...
@@ -237,12 +419,36 @@ class MyApp extends StatelessWidget {
ChangeNotifierProvider
(
create:
(
_
)
=>
RewardListProvider
()),
ChangeNotifierProvider
(
create:
(
_
)
=>
LeaveApplicationListProvider
()),
ChangeNotifierProvider
(
create:
(
_
)
=>
Orgprovider
()),
ChangeNotifierProvider
(
create:
(
_
)
=>
AdvanceListProvider
()),
ChangeNotifierProvider
(
create:
(
_
)
=>
CasualLeaveHistoryProvider
()),
],
child:
Builder
(
builder:
(
BuildContext
context
)
{
return
MaterialApp
(
navigatorKey:
navigatorKey
,
routes:
{
'/home'
:
(
context
)
=>
const
AttendanceScreen
(),
'/chat'
:
(
context
)
=>
AttendanceScreen
(),
'/product_details'
:
(
context
)
=>
AttendanceScreen
(),
'/order_details'
:
(
context
)
=>
AttendanceScreen
(),
'/crm_lead_list'
:
(
context
)
=>
LeadDetailsByMode
(
mode:
""
,
pageTitleName:
"Lead Details"
,
leadId:
""
),
'/crm_prospect_list'
:
(
context
)
=>
ProspectListByMode
(),
'/crm_prospect_details'
:
(
context
)
=>
AttendanceScreen
(),
'/crm_lead_details'
:
(
context
)
=>
AttendanceScreen
(),
'/dashboard'
:
(
context
)
=>
CrmdashboardScreen
(),
'/crm_new_customer_new_lead_register'
:
(
context
)
=>
AttendanceScreen
(),
'/crm_prospect_list_team'
:
(
context
)
=>
AttendanceScreen
(),
'/crm_prospect_list_admin'
:
(
context
)
=>
AttendanceScreen
(),
'/finance_list_employee'
:
(
context
)
=>
AttendanceScreen
(),
'/finance_list_admin'
:
(
context
)
=>
AttendanceScreen
(),
'/dispatch_list_executive'
:
(
context
)
=>
AttendanceScreen
(),
'/tour_bill_list'
:
(
context
)
=>
TourExpensesListScreen
(),
'/manual_attendance_request_list'
:
(
context
)
=>
AttendanceListScreen
(
mode:
""
,),
},
scrollBehavior:
const
MaterialScrollBehavior
().
copyWith
(
dragDevices:
{
PointerDeviceKind
.
touch
,
PointerDeviceKind
.
mouse
},
dragDevices:
{
PointerDeviceKind
.
touch
,
PointerDeviceKind
.
mouse
},
),
navigatorObservers:
[
MyNavigatorObserver
()],
...
...
@@ -261,6 +467,7 @@ class MyApp extends StatelessWidget {
highlightColor:
Colors
.
transparent
,
hoverColor:
Colors
.
transparent
,
scaffoldBackgroundColor:
Colors
.
white
,
dialogBackgroundColor:
Colors
.
white
,
cardColor:
Colors
.
white
,
shadowColor:
Colors
.
white54
,
searchBarTheme:
const
SearchBarThemeData
(),
...
...
@@ -304,8 +511,8 @@ class MyApp extends StatelessWidget {
dragHandleSize:
Size
(
60.0
,
6.0
),
),
colorScheme:
const
ColorScheme
.
light
(
surface
:
Colors
.
white
,
).
copyWith
(
surface
:
Colors
.
white
),
background
:
Colors
.
white
,
).
copyWith
(
background
:
Colors
.
white
),
scrollbarTheme:
ScrollbarThemeData
(
minThumbLength:
20
,
interactive:
true
,
...
...
@@ -316,8 +523,10 @@ class MyApp extends StatelessWidget {
),
),
checkboxTheme:
CheckboxThemeData
(
side:
BorderSide
(
width:
0.5
),
checkColor:
WidgetStatePropertyAll
(
AppColors
.
white
),
),
useMaterial3:
true
,
// inputDecorationTheme: InputDecorationTheme(
...
...
lib/screens/HomeScreen.dart
View file @
dc88a3f9
...
...
@@ -1779,12 +1779,12 @@ class _MyHomePageState extends State<MyHomePage> {
}
Future
<
void
>
_showProfileBottomSheet
(
BuildContext
context
)
{
final
profileNotifier
=
Provider
.
of
<
ProfileNotifer
>(
context
,
listen:
false
);
//
final profileNotifier = Provider.of<ProfileNotifer>(context, listen: false);
profileNotifier
.
fetchJobDescription
(
Provider
.
of
<
HomescreenNotifier
>(
context
,
listen:
false
),
context
,
);
//
profileNotifier.fetchJobDescription(
//
Provider.of<HomescreenNotifier>(context, listen: false),
//
context,
//
);
return
showModalBottomSheet
(
useSafeArea:
true
,
isDismissible:
true
,
...
...
@@ -1975,18 +1975,7 @@ class _MyHomePageState extends State<MyHomePage> {
AppColors
.
semi_black
,
),
),
if
(
profileNotifier
.
response
?.
jobDescription
?.
jobDescription
!=
null
&&
profileNotifier
.
response
!
.
jobDescription
!
.
jobDescription
!=
""
)
if
(
index
==
2
)
// only for Designation
if
(
index
==
2
)
// only for Designation
InkWell
(
onTap:
index
==
2
...
...
lib/screens/crm/LeadDetailsByMode.dart
View file @
dc88a3f9
...
...
@@ -797,7 +797,7 @@ class _LeadDetailsByModeState extends State<LeadDetailsByMode> {
if
(
productsNotEmpty
)
...[
SizedBox
(
width:
double
.
infinity
,
height:
1
3
0
,
height:
1
5
0
,
child:
ListView
.
builder
(
physics:
AlwaysScrollableScrollPhysics
(),
shrinkWrap:
true
,
...
...
@@ -872,7 +872,7 @@ class _LeadDetailsByModeState extends State<LeadDetailsByMode> {
);
},
child:
Container
(
height:
1
3
0
,
height:
1
4
0
,
width:
MediaQuery
.
of
(
context
).
size
.
width
*
0.9
,
...
...
@@ -966,7 +966,7 @@ class _LeadDetailsByModeState extends State<LeadDetailsByMode> {
AppColors
.
grey_semi
,
),
),
SizedBox
(
height:
5
),
SizedBox
(
height:
3
),
DottedLine
(
dashGapLength:
4
,
dashGapColor:
...
...
@@ -988,6 +988,24 @@ class _LeadDetailsByModeState extends State<LeadDetailsByMode> {
.
semi_black
,
),
),
SizedBox
(
height:
5
),
Row
(
mainAxisAlignment:
MainAxisAlignment
.
spaceBetween
,
children:
[
Expanded
(
child:
Text
(
provider
.
leadProducts
[
lp
].
remarks
??
""
,
style:
TextStyle
(
fontFamily:
"JakartaMedium"
,
fontSize:
14
,
color:
AppColors
.
semi_black
,
),
maxLines:
1
,
overflow:
TextOverflow
.
ellipsis
,
),
),
],
)
],
),
),
...
...
@@ -3458,6 +3476,34 @@ class _LeadDetailsByModeState extends State<LeadDetailsByMode> {
),
],
),
const
SizedBox
(
height:
10
),
TextWidget
(
context
,
"Remarks"
),
Container
(
margin:
EdgeInsets
.
only
(
bottom:
6
),
decoration:
BoxDecoration
(
color:
AppColors
.
text_field_color
,
borderRadius:
BorderRadius
.
circular
(
14
),
),
child:
TextFormField
(
controller:
editProvider
.
addEditRemarkController
,
maxLines:
3
,
enabled:
true
,
style:
TextStyle
(
color:
Colors
.
black
,
fontSize:
14
,
),
decoration:
InputDecoration
(
hintText:
"Enter remark"
,
hintStyle:
TextStyle
(
color:
Colors
.
grey
.
shade500
,
fontSize:
14
,
),
border:
InputBorder
.
none
,
contentPadding:
EdgeInsets
.
symmetric
(
horizontal:
12
,
vertical:
12
),
),
),
),
// IconButton(
// icon: const Icon(Icons.delete),
// onPressed: editProvider.editProductPriceControllers.length > 1
...
...
@@ -3476,8 +3522,8 @@ class _LeadDetailsByModeState extends State<LeadDetailsByMode> {
provider
.
leadDetails
.
id
!,
type
,
leadProductId
,
editProvider
.
selectedAddEditProductId
,
editProvider
.
selectedAddEditProductId
,
editProvider
.
addEditRemarkController
);
},
child:
Container
(
...
...
lib/screens/crm/LeadListByMode.dart
View file @
dc88a3f9
...
...
@@ -272,9 +272,7 @@ class _LeadlistbymodeState extends State<Leadlistbymode> {
child:
InkResponse
(
onTap:
()
{
HapticFeedback
.
selectionClick
();
launch
(
'tel://
${crmLists[index].mob1}
'
,
);
_showContactOptions
(
context
,
crmLists
[
index
].
mob1
);
},
child:
SizedBox
(
height:
35
,
...
...
@@ -930,6 +928,91 @@ class _LeadlistbymodeState extends State<Leadlistbymode> {
},
);
}
void
_showContactOptions
(
BuildContext
context
,
String
?
phoneNumber
)
{
if
(
phoneNumber
==
null
||
phoneNumber
.
isEmpty
)
{
ScaffoldMessenger
.
of
(
context
).
showSnackBar
(
const
SnackBar
(
content:
Text
(
"No phone number available"
)),
);
return
;
}
showModalBottomSheet
(
context:
context
,
shape:
const
RoundedRectangleBorder
(
borderRadius:
BorderRadius
.
vertical
(
top:
Radius
.
circular
(
20
)),
),
backgroundColor:
Colors
.
white
,
builder:
(
BuildContext
context
)
{
return
Padding
(
padding:
const
EdgeInsets
.
symmetric
(
vertical:
16
,
horizontal:
20
),
child:
Column
(
mainAxisSize:
MainAxisSize
.
min
,
children:
[
Container
(
width:
40
,
height:
4
,
decoration:
BoxDecoration
(
color:
Colors
.
grey
.
shade400
,
borderRadius:
BorderRadius
.
circular
(
10
),
),
),
const
SizedBox
(
height:
16
),
const
Text
(
"Contact Options"
,
style:
TextStyle
(
fontSize:
18
,
fontWeight:
FontWeight
.
w600
,
fontFamily:
"JakartaMedium"
,
color:
Colors
.
black
),
),
const
SizedBox
(
height:
20
),
// --- Call Option ---
ListTile
(
leading:
const
Icon
(
Icons
.
phone
,
color:
Colors
.
green
),
title:
const
Text
(
"Call"
,
style:
TextStyle
(
fontSize:
16
,
fontFamily:
"JakartaMedium"
,
)
),
onTap:
()
async
{
Navigator
.
pop
(
context
);
final
uri
=
Uri
.
parse
(
"tel:
$phoneNumber
"
);
await
launchUrl
(
uri
,
mode:
LaunchMode
.
externalApplication
);
},
),
// --- WhatsApp Option ---
ListTile
(
leading:
const
Icon
(
Icons
.
chat
,
color:
Colors
.
teal
),
title:
const
Text
(
"WhatsApp"
,
style:
TextStyle
(
fontSize:
16
,
fontFamily:
"JakartaMedium"
,
)
),
onTap:
()
async
{
Navigator
.
pop
(
context
);
final
message
=
Uri
.
encodeComponent
(
"Hello, I’d like to connect with you."
);
final
whatsappUri
=
Uri
.
parse
(
"https://wa.me/
$phoneNumber
?text=
$message
"
);
if
(
await
canLaunchUrl
(
whatsappUri
))
{
await
launchUrl
(
whatsappUri
,
mode:
LaunchMode
.
externalApplication
);
}
else
{
ScaffoldMessenger
.
of
(
context
).
showSnackBar
(
const
SnackBar
(
content:
Text
(
"WhatsApp not installed or invalid number"
)),
);
}
},
),
],
),
);
},
);
}
bool
_isFilterSelected
(
Leadlistprovider
provider
,
int
index
)
{
switch
(
index
)
{
...
...
lib/screens/crm/ProspectDetailsByMode.dart
View file @
dc88a3f9
...
...
@@ -3375,43 +3375,43 @@ class ProspectDetailsByModeState extends State<ProspectDetailsByMode> {
children:
[
Expanded
(
child:
DropdownButton2
<
String
>(
hint:
Text
(
"Select Status"
,
isExpanded:
true
,
hint:
const
Row
(
children:
[
Expanded
(
child:
Text
(
'Select Lead Status'
,
style:
TextStyle
(
fontSize:
14
),
overflow:
TextOverflow
.
ellipsis
,
),
),
],
),
items:
addleadProvider
.
statusList
<
String
>[
'All'
,
'Cold'
,
'Hot'
,
'Warm'
]
.
map
(
(
slist
)
=>
DropdownMenuItem
<
String
>(
value:
slist
,
(
value
)
=>
DropdownMenuItem
<
String
>(
value:
value
,
child:
Text
(
slist
,
style:
TextStyle
(
value
??
''
,
style:
const
TextStyle
(
fontSize:
14
,
),
overflow:
TextOverflow
.
ellipsis
,
),
),
)
.
toList
(),
value:
addleadProvider
.
selectedStatus
,
onChanged:
(
String
?
value
)
{
if
(
value
!=
null
)
{
if
(
addleadProvider
.
statusList
.
isNotEmpty
)
{
addleadProvider
.
selectedStatus
=
value
;
}
}
onChanged:
(
String
?
newValue
)
{
setState
(()
{
addleadProvider
.
selectedStatus
=
newValue
!;
});
},
isExpanded:
true
,
buttonStyleData:
ddtheme
.
buttonStyleData
,
iconStyleData:
ddtheme
.
iconStyleData
,
menuItemStyleData:
ddtheme
.
menuItemStyleData
,
dropdownStyleData:
ddtheme
.
dropdownStyleData
,
menuItemStyleData:
ddtheme
.
menuItemStyleData
,
dropdownStyleData:
ddtheme
.
dropdownStyleData
,
),
),
],
...
...
@@ -3421,6 +3421,34 @@ class ProspectDetailsByModeState extends State<ProspectDetailsByMode> {
errorWidget
(
context
,
addleadProvider
.
statusError
),
],
TextWidget
(
context
,
"Remarks"
),
Container
(
margin:
EdgeInsets
.
only
(
bottom:
6
),
decoration:
BoxDecoration
(
color:
AppColors
.
text_field_color
,
borderRadius:
BorderRadius
.
circular
(
14
),
),
child:
TextFormField
(
controller:
addleadProvider
.
addLeadProductRemarksController
,
maxLines:
3
,
enabled:
true
,
style:
TextStyle
(
color:
Colors
.
black
,
fontSize:
14
,
),
decoration:
InputDecoration
(
hintText:
"Enter remark"
,
hintStyle:
TextStyle
(
color:
Colors
.
grey
.
shade500
,
fontSize:
14
,
),
border:
InputBorder
.
none
,
contentPadding:
EdgeInsets
.
symmetric
(
horizontal:
12
,
vertical:
12
),
),
),
),
InkResponse
(
onTap:
addleadProvider
.
submitLoading
...
...
lib/screens/crm/addLeadProductScreen.dart
View file @
dc88a3f9
...
...
@@ -29,7 +29,6 @@ class _AddleadproductscreenState extends State<Addleadproductscreen> {
@override
void
initState
()
{
// TODO: implement initState
super
.
initState
();
_connectivity
.
initialise
();
_connectivity
.
myStream
.
listen
((
source
)
{
...
...
@@ -47,17 +46,15 @@ class _AddleadproductscreenState extends State<Addleadproductscreen> {
provider
.
addProductPriceController
.
clear
();
provider
.
addQuantityController
.
clear
();
provider
.
addTotalAmountController
.
clear
();
provider
.
remarkController
.
clear
();
// Clear remarks too
}
else
{
provider
.
prefillProductForEdit
(
widget
.
editIndex
!);
}
// provider.addEditInitializeForm(context);
});
}
@override
void
dispose
()
{
// TODO: implement dispose
super
.
dispose
();
_connectivity
.
disposeStream
();
}
...
...
@@ -94,7 +91,6 @@ class _AddleadproductscreenState extends State<Addleadproductscreen> {
builder:
(
context
,
provider
,
child
)
{
return
Scaffold
(
resizeToAvoidBottomInset:
true
,
appBar:
appbarNew
(
context
,
"Generate Quotation"
,
0xFFFFFFFF
),
backgroundColor:
AppColors
.
scaffold_bg_color
,
body:
SingleChildScrollView
(
...
...
@@ -109,7 +105,6 @@ class _AddleadproductscreenState extends State<Addleadproductscreen> {
horizontal:
10
,
vertical:
10
,
),
decoration:
BoxDecoration
(
color:
Colors
.
white
,
borderRadius:
BorderRadius
.
circular
(
20
),
...
...
@@ -129,8 +124,7 @@ class _AddleadproductscreenState extends State<Addleadproductscreen> {
style:
TextStyle
(
fontSize:
14
),
overflow:
TextOverflow
.
ellipsis
,
),
items:
provider
.
productsList
items:
provider
.
productsList
.
map
(
(
ord
)
=>
DropdownMenuItem
<
Products
>(
value:
ord
,
...
...
@@ -144,18 +138,7 @@ class _AddleadproductscreenState extends State<Addleadproductscreen> {
),
)
.
toList
(),
// provider.selectedOrderIds[index] != null?
// provider
// .orderList
// .firstWhere(
// (product) =>
// product
// .orderId ==
// provider
// .selectedOrderIds[index],
// )
value:
provider
.
selectedProducts
!=
null
value:
provider
.
selectedProducts
!=
null
?
provider
.
productsList
.
firstWhere
(
(
element
)
=>
element
.
id
==
...
...
@@ -167,12 +150,12 @@ class _AddleadproductscreenState extends State<Addleadproductscreen> {
provider
.
selectedProducts
=
value
;
provider
.
selectedProductsId
=
value
.
id
!;
provider
.
selectedProductsValue
=
value
.
name
;
}
provider
.
selectedProductsRemark
=
value
.
remarks
;
provider
.
crmSelectedProductDetailsApiFunction
(
context
,
value
!
.
id
.
toString
(),
value
.
id
.
toString
(),
);
}
},
dropdownSearchData:
DropdownSearchData
(
searchInnerWidgetHeight:
50
,
...
...
@@ -222,7 +205,6 @@ class _AddleadproductscreenState extends State<Addleadproductscreen> {
],
),
),
const
SizedBox
(
height:
10
),
textControllerWidget
(
context
,
...
...
@@ -263,54 +245,133 @@ class _AddleadproductscreenState extends State<Addleadproductscreen> {
),
],
),
// IconButton(
// icon: const Icon(Icons.delete),
// onPressed: provider.editProductPriceControllers.length > 1
// ? () => provider.editRemoveRow(j)
// : null,
// ),
TextWidget
(
context
,
"Remarks"
),
Container
(
margin:
EdgeInsets
.
only
(
bottom:
6
),
decoration:
BoxDecoration
(
color:
AppColors
.
text_field_color
,
borderRadius:
BorderRadius
.
circular
(
14
),
),
child:
TextFormField
(
controller:
provider
.
remarkController
,
maxLines:
3
,
enabled:
true
,
style:
TextStyle
(
color:
Colors
.
black
,
fontSize:
14
,
),
decoration:
InputDecoration
(
hintText:
"Enter remark"
,
hintStyle:
TextStyle
(
color:
Colors
.
grey
.
shade500
,
fontSize:
14
,
),
border:
InputBorder
.
none
,
contentPadding:
EdgeInsets
.
symmetric
(
horizontal:
12
,
vertical:
12
),
),
),
)
],
),
),
],
),
),
floatingActionButtonLocation:
FloatingActionButtonLocation
.
centerFloat
,
floatingActionButton:
InkWell
(
onTap:
()
{
HapticFeedback
.
selectionClick
();
if
(
provider
.
selectedProducts
!=
null
)
{
// Validate required fields
if
(
provider
.
selectedProducts
==
null
)
{
ScaffoldMessenger
.
of
(
context
).
showSnackBar
(
SnackBar
(
content:
Text
(
"Please select a product"
),
backgroundColor:
Colors
.
red
,
duration:
Duration
(
seconds:
2
),
),
);
return
;
}
if
(
provider
.
addProductPriceController
.
text
.
isEmpty
)
{
ScaffoldMessenger
.
of
(
context
).
showSnackBar
(
SnackBar
(
content:
Text
(
"Please enter product price"
),
backgroundColor:
Colors
.
red
,
duration:
Duration
(
seconds:
2
),
),
);
return
;
}
if
(
provider
.
addQuantityController
.
text
.
isEmpty
)
{
ScaffoldMessenger
.
of
(
context
).
showSnackBar
(
SnackBar
(
content:
Text
(
"Please enter quantity"
),
backgroundColor:
Colors
.
red
,
duration:
Duration
(
seconds:
2
),
),
);
return
;
}
// Prepare product data - FIX: Use .text for remarks
final
productData
=
{
"product_id"
:
provider
.
selectedProductsId
!,
"price"
:
provider
.
addProductPriceController
.
text
,
"qty"
:
provider
.
addQuantityController
.
text
,
"net_price"
:
provider
.
addTotalAmountController
.
text
,
"remarks"
:
provider
.
remarkController
.
text
,
// FIXED: Use .text
};
if
(
widget
.
editIndex
!=
null
)
{
provider
.
updateProduct
(
widget
.
editIndex
!,
productData
);
print
(
"Product updated at index
${widget.editIndex}
"
);
}
else
{
provider
.
addProduct
(
productData
);
print
(
"New product added"
);
}
print
(
provider
.
getJsonEncodedProducts
());
Navigator
.
pop
(
context
,
provider
.
getJsonEncodedProducts
());
print
(
"Product data:
${provider.getJsonEncodedProducts()}
"
);
// Show success message
ScaffoldMessenger
.
of
(
context
).
showSnackBar
(
SnackBar
(
content:
Text
(
widget
.
editIndex
!=
null
?
"Product updated successfully!"
:
"Product added successfully!"
),
backgroundColor:
Colors
.
green
,
duration:
Duration
(
seconds:
2
),
),
);
// Close screen after a short delay to show the success message
Future
.
delayed
(
Duration
(
milliseconds:
1500
),
()
{
if
(
mounted
)
{
Navigator
.
pop
(
context
,
true
);
// Return true to indicate success
}
});
},
child:
Container
(
alignment:
Alignment
.
center
,
height:
45
,
decoration:
BoxDecoration
(
color:
AppColors
.
app_blue
,
//1487C9
color:
AppColors
.
app_blue
,
borderRadius:
BorderRadius
.
circular
(
14.0
),
),
margin:
EdgeInsets
.
symmetric
(
horizontal:
10
),
child:
Center
(
child:
Text
(
"Submi
t"
,
widget
.
editIndex
!=
null
?
"Update Product"
:
"Add Produc
t"
,
textAlign:
TextAlign
.
center
,
style:
TextStyle
(
color:
Colors
.
white
),
style:
TextStyle
(
color:
Colors
.
white
,
fontSize:
16
,
fontWeight:
FontWeight
.
w600
,
),
),
),
),
...
...
@@ -319,4 +380,18 @@ class _AddleadproductscreenState extends State<Addleadproductscreen> {
},
);
}
Widget
TextWidget
(
context
,
text
)
{
return
Padding
(
padding:
const
EdgeInsets
.
only
(
bottom:
5.0
,
top:
8.0
),
child:
Text
(
text
,
style:
TextStyle
(
fontSize:
14
,
fontWeight:
FontWeight
.
w500
,
color:
AppColors
.
semi_black
,
),
),
);
}
}
\ No newline at end of file
lib/screens/crm/addLeadsProspectsScreen.dart
View file @
dc88a3f9
...
...
@@ -304,7 +304,7 @@ class _AddleadsprospectsscreenState extends State<Addleadsprospectsscreen> {
provider
.
contactPersonNameController
,
"Contact Person Name"
,
"Enter Name"
,
provider
.
onChangeContactPersonName
,
(
value
)
=>
provider
.
onChangeContactPersonName
(
context
,
value
)
,
TextInputType
.
name
,
false
,
null
,
...
...
@@ -312,6 +312,7 @@ class _AddleadsprospectsscreenState extends State<Addleadsprospectsscreen> {
focusNodes
[
2
],
TextInputAction
.
next
,
),
errorWidget
(
context
,
provider
.
nameError
),
textControllerWidget
(
...
...
@@ -319,7 +320,7 @@ class _AddleadsprospectsscreenState extends State<Addleadsprospectsscreen> {
provider
.
mobileController
,
"Mobile Number"
,
"Enter Mobile Number"
,
provider
.
onChangemobile
,
(
value
)
=>
provider
.
onChangemobile
(
context
,
value
)
,
TextInputType
.
phone
,
false
,
FilteringTextInputFormatter
.
digitsOnly
,
...
...
@@ -931,16 +932,11 @@ class _AddleadsprospectsscreenState extends State<Addleadsprospectsscreen> {
scrollDirection:
Axis
.
horizontal
,
itemCount:
provider
.
productRows
.
length
,
itemBuilder:
(
context
,
index
)
{
final
product
=
provider
.
productRows
[
index
];
final
productName
=
provider
.
productsList
final
product
=
provider
.
productRows
[
index
];
final
productName
=
provider
.
productsList
.
firstWhere
(
(
p
)
=>
p
.
id
==
product
[
'product_id'
],
orElse:
()
=>
Products
(
(
p
)
=>
p
.
id
==
product
[
'product_id'
],
orElse:
()
=>
Products
(
id:
''
,
name:
'Unknown'
,
),
...
...
@@ -948,23 +944,24 @@ class _AddleadsprospectsscreenState extends State<Addleadsprospectsscreen> {
.
name
;
final
prodPrice
=
product
[
'price'
]
??
'-'
;
final
prodQty
=
product
[
'qty'
]
??
'-'
;
final
totalPrice
=
product
[
'net_price'
]
??
'-'
;
final
totalPrice
=
product
[
'net_price'
]
??
'-'
;
// FIX: Get the text from TextEditingController, not the controller itself
final
remark
=
product
[
'remarks'
]
is
TextEditingController
?
(
product
[
'remarks'
]
as
TextEditingController
).
text
:
product
[
'remarks'
]?.
toString
()
??
''
;
return
InkResponse
(
onTap:
()
async
{
var
res
=
await
Navigator
.
push
(
context
,
MaterialPageRoute
(
builder:
(
context
)
=>
Addleadproductscreen
(
builder:
(
context
)
=>
Addleadproductscreen
(
type:
"Edit"
,
editIndex:
index
,
),
settings:
RouteSettings
(
name:
'Generatequotationaddeditproduct'
,
name:
'Generatequotationaddeditproduct'
,
),
),
);
...
...
@@ -973,21 +970,10 @@ class _AddleadsprospectsscreenState extends State<Addleadsprospectsscreen> {
}
},
child:
Container
(
width:
MediaQuery
.
of
(
context
,
).
size
.
width
*
0.8
,
width:
MediaQuery
.
of
(
context
).
size
.
width
*
0.8
,
margin:
EdgeInsets
.
only
(
left:
index
==
0
?
10
:
5
,
right:
index
==
provider
.
productRows
.
length
-
1
?
10
:
5
,
right:
index
==
provider
.
productRows
.
length
-
1
?
10
:
5
,
bottom:
5
,
),
padding:
EdgeInsets
.
symmetric
(
...
...
@@ -996,15 +982,11 @@ class _AddleadsprospectsscreenState extends State<Addleadsprospectsscreen> {
),
decoration:
BoxDecoration
(
color:
Color
(
0xFFE6F6FF
),
borderRadius:
BorderRadius
.
circular
(
14
,
),
borderRadius:
BorderRadius
.
circular
(
14
),
),
child:
Row
(
mainAxisAlignment:
MainAxisAlignment
.
start
,
crossAxisAlignment:
CrossAxisAlignment
.
start
,
mainAxisAlignment:
MainAxisAlignment
.
start
,
crossAxisAlignment:
CrossAxisAlignment
.
start
,
children:
[
Expanded
(
flex:
1
,
...
...
@@ -1016,10 +998,8 @@ class _AddleadsprospectsscreenState extends State<Addleadsprospectsscreen> {
Expanded
(
flex:
6
,
child:
Column
(
crossAxisAlignment:
CrossAxisAlignment
.
start
,
mainAxisAlignment:
MainAxisAlignment
.
start
,
crossAxisAlignment:
CrossAxisAlignment
.
start
,
mainAxisAlignment:
MainAxisAlignment
.
start
,
children:
[
Row
(
children:
[
...
...
@@ -1028,32 +1008,23 @@ class _AddleadsprospectsscreenState extends State<Addleadsprospectsscreen> {
child:
Text
(
productName
??
"-"
,
maxLines:
2
,
overflow:
TextOverflow
.
ellipsis
,
overflow:
TextOverflow
.
ellipsis
,
style:
TextStyle
(
fontFamily:
"JakartaMedium"
,
fontFamily:
"JakartaMedium"
,
fontSize:
14
,
color:
AppColors
.
semi_black
,
color:
AppColors
.
semi_black
,
),
),
),
Expanded
(
flex:
3
,
child:
Text
(
textAlign:
TextAlign
.
right
,
textAlign:
TextAlign
.
right
,
"₹
$prodPrice
"
,
style:
TextStyle
(
fontFamily:
"JakartaMedium"
,
fontFamily:
"JakartaMedium"
,
fontSize:
14
,
color:
AppColors
.
semi_black
,
color:
AppColors
.
semi_black
,
),
),
),
...
...
@@ -1062,42 +1033,51 @@ class _AddleadsprospectsscreenState extends State<Addleadsprospectsscreen> {
Text
(
"x
$prodQty
"
,
style:
TextStyle
(
fontFamily:
"JakartaMedium"
,
fontFamily:
"JakartaMedium"
,
fontSize:
14
,
color:
AppColors
.
grey_semi
,
color:
AppColors
.
grey_semi
,
),
),
SizedBox
(
height:
5
),
DottedLine
(
dashGapLength:
4
,
dashGapColor:
Colors
.
white
,
dashColor:
AppColors
.
grey_semi
,
dashGapColor:
Colors
.
white
,
dashColor:
AppColors
.
grey_semi
,
dashLength:
2
,
lineThickness:
0.5
,
),
SizedBox
(
height:
5
),
Row
(
mainAxisAlignment:
MainAxisAlignment
.
spaceBetween
,
mainAxisAlignment:
MainAxisAlignment
.
spaceBetween
,
children:
[
Text
(
"₹
$totalPrice
"
,
style:
TextStyle
(
fontFamily:
"JakartaMedium"
,
fontFamily:
"JakartaMedium"
,
fontSize:
14
,
color:
AppColors
.
semi_black
,
color:
AppColors
.
semi_black
,
),
),
],
),
SizedBox
(
height:
5
),
Row
(
mainAxisAlignment:
MainAxisAlignment
.
spaceBetween
,
children:
[
Expanded
(
child:
Text
(
remark
,
// Now this is a String, not a TextEditingController
style:
TextStyle
(
fontFamily:
"JakartaMedium"
,
fontSize:
14
,
color:
AppColors
.
semi_black
,
),
maxLines:
1
,
overflow:
TextOverflow
.
ellipsis
,
),
),
],
)
],
),
),
...
...
lib/screens/crm/followUpUpdateScreen.dart
View file @
dc88a3f9
...
...
@@ -11,6 +11,8 @@ import 'package:generp/Utils/commonWidgets.dart';
import
'package:generp/Utils/dropdownTheme.dart'
;
import
'package:provider/provider.dart'
;
import
'../order/ordersListByModes.dart'
;
class
Followupupdatescreen
extends
StatefulWidget
{
final
leadID
;
final
mode
;
...
...
@@ -391,7 +393,7 @@ class _FollowupupdatescreenState extends State<Followupupdatescreen> {
),
items:
<
String
>[
//
'Order Gain',
'Order Gain'
,
'Order Lost'
,
'No Requirement'
,
]
...
...
@@ -709,6 +711,9 @@ class _FollowupupdatescreenState extends State<Followupupdatescreen> {
provider
.
selectedCompetitor
,
provider
.
selectedLeadStatus
,
provider
.
selectNextAppointmentType
,
provider
.
followUpFeedbackController
,
provider
.
selectedTime
,
provider
.
currentLocationLatLng
,
provider
.
smsSent
,
widget
.
mode
,
);
...
...
lib/screens/crm/generateQuotationScreen.dart
View file @
dc88a3f9
...
...
@@ -175,14 +175,19 @@ class _GeneratequotationscreenState extends State<Generatequotationscreen> {
),
),
);
if
(
res
!=
null
)
{
if
(
res
!=
null
&&
res
==
true
)
{
print
(
"result
$res
"
);
// provider
// .crmLeadDetailsGenerateQuoteViewAPIFunction(
// context,
// widget.leadId,
// );
// Force refresh the provider and UI
await
provider
.
crmLeadDetailsGenerateQuoteViewAPIFunction
(
context
,
widget
.
leadId
,
);
// Force UI update
if
(
mounted
)
{
setState
(()
{});
}
}
},
child:
Container
(
...
...
@@ -244,15 +249,24 @@ class _GeneratequotationscreenState extends State<Generatequotationscreen> {
),
),
);
if
(
res
!=
null
)
{
if
(
res
!=
null
&&
res
==
true
)
{
print
(
"result
$res
"
);
// Force refresh after editing
await
provider
.
crmLeadDetailsGenerateQuoteViewAPIFunction
(
context
,
widget
.
leadId
,
);
// Force UI update
if
(
mounted
)
{
setState
(()
{});
}
}
},
child:
Container
(
height:
115
,
width:
MediaQuery
.
of
(
context
).
size
.
width
*
0.8
,
height:
125
,
width:
MediaQuery
.
of
(
context
).
size
.
width
*
0.8
,
decoration:
BoxDecoration
(
color:
Color
(
0xFFE6F6FF
),
borderRadius:
BorderRadius
.
circular
(
14
),
...
...
@@ -261,17 +275,12 @@ class _GeneratequotationscreenState extends State<Generatequotationscreen> {
horizontal:
10
,
vertical:
8
,
),
margin:
EdgeInsets
.
symmetric
(
horizontal:
5
,
// vertical: 10,
),
child:
Row
(
mainAxisAlignment:
MainAxisAlignment
.
start
,
crossAxisAlignment:
CrossAxisAlignment
.
start
,
mainAxisAlignment:
MainAxisAlignment
.
start
,
crossAxisAlignment:
CrossAxisAlignment
.
start
,
children:
[
Expanded
(
flex:
1
,
...
...
@@ -282,89 +291,79 @@ class _GeneratequotationscreenState extends State<Generatequotationscreen> {
SizedBox
(
width:
10
),
Expanded
(
flex:
6
,
child:
SizedBox
(
child:
Column
(
// mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment:
CrossAxisAlignment
.
start
,
mainAxisAlignment:
MainAxisAlignment
.
start
,
crossAxisAlignment:
CrossAxisAlignment
.
start
,
mainAxisAlignment:
MainAxisAlignment
.
spaceBetween
,
// Changed to spaceBetween
children:
[
// Top section - Product name and price
Column
(
crossAxisAlignment:
CrossAxisAlignment
.
start
,
children:
[
Row
(
children:
[
Expanded
(
flex:
4
,
child:
Text
(
provider
.
leadProductsList
[
lp
]
.
productName
??
"-"
,
provider
.
leadProductsList
[
lp
].
productName
??
"-"
,
maxLines:
1
,
overflow:
TextOverflow
.
ellipsis
,
overflow:
TextOverflow
.
ellipsis
,
style:
TextStyle
(
fontFamily:
"JakartaMedium"
,
fontFamily:
"JakartaMedium"
,
fontSize:
14
,
color:
AppColors
.
semi_black
,
color:
AppColors
.
semi_black
,
),
),
),
Expanded
(
flex:
2
,
flex:
3
,
child:
Text
(
textAlign:
TextAlign
.
right
,
textAlign:
TextAlign
.
right
,
maxLines:
1
,
"₹
${provider.leadProductsList[lp].price ?? "-"}
"
,
style:
TextStyle
(
fontFamily:
"JakartaMedium"
,
fontFamily:
"JakartaMedium"
,
fontSize:
14
,
color:
AppColors
.
semi_black
,
color:
AppColors
.
semi_black
,
),
),
),
],
),
SizedBox
(
height:
1
),
// Reduced spacing
Text
(
"x
${provider.leadProductsList[lp].qty ?? "-"}
"
,
style:
TextStyle
(
fontFamily:
"JakartaMedium"
,
fontSize:
14
,
color:
AppColors
.
grey_semi
,
fontFamily:
"JakartaMedium"
,
fontSize:
12
,
// Slightly smaller font
color:
AppColors
.
grey_semi
,
),
),
SizedBox
(
height:
5
),
DottedLine
(
],
),
// Middle section - Dotted line
Center
(
child:
DottedLine
(
dashGapLength:
4
,
dashGapColor:
Colors
.
white
,
dashColor:
AppColors
.
grey_semi
,
dashColor:
AppColors
.
grey_semi
,
dashLength:
2
,
lineThickness:
0.5
,
),
SizedBox
(
height:
5
),
),
// Bottom section - Total price
Text
(
"₹
${provider.leadProductsList[lp].prodTotalPrice ?? " - "}
"
,
style:
TextStyle
(
fontFamily:
"JakartaMedium"
,
fontFamily:
"JakartaMedium"
,
fontSize:
14
,
color:
AppColors
.
semi_black
,
color:
AppColors
.
semi_black
,
),
),
],
),
),
),
],
),
),
...
...
@@ -374,192 +373,6 @@ class _GeneratequotationscreenState extends State<Generatequotationscreen> {
),
],
errorWidget
(
context
,
provider
.
productRowsError
),
// if (provider.leadProductsList.isNotEmpty ||
// provider
// .editProductPriceControllers
// .isNotEmpty) ...[
// ListView.builder(
// itemCount:
// provider.editProductPriceControllers.length,
// physics: const NeverScrollableScrollPhysics(),
// shrinkWrap: true,
// itemBuilder: (context, j) {
// return Container(
// padding: const EdgeInsets.symmetric(
// horizontal: 10,
// vertical: 10,
// ),
// margin: const EdgeInsets.symmetric(
// vertical: 10,
// ),
// decoration: BoxDecoration(
// color: Colors.white,
// borderRadius: BorderRadius.circular(20),
// ),
// child: Column(
// crossAxisAlignment:
// CrossAxisAlignment.start,
// children: [
// TextWidget(context, "Product"),
// DropdownButtonHideUnderline(
// child: Row(
// children: [
// Expanded(
// child: DropdownButton2<
// LeadProducts
// >(
// isExpanded: true,
// hint: const Text(
// 'Select Product',
// style: TextStyle(
// fontSize: 14,
// ),
// overflow:
// TextOverflow.ellipsis,
// ),
// items:
// provider.leadProductsList
// .map(
// (
// ord,
// ) => DropdownMenuItem<
// LeadProducts
// >(
// value: ord,
// child: Text(
// "(Product Name: ${ord.productName})",
// style:
// const TextStyle(
// fontSize:
// 14,
// ),
// overflow:
// TextOverflow
// .ellipsis,
// ),
// ),
// )
// .toList(),
// value:
// provider.selectedProductIds[j] !=
// null
// ? provider
// .leadProductsList
// .firstWhere(
// (ord) =>
// ord.id ==
// provider
// .selectedProductIds[j],
// orElse:
// () =>
// provider
// .leadProductsList[0],
// )
// : null,
// onChanged: (
// LeadProducts? value,
// ) {
// if (value != null) {
// provider
// .updateSelectedProductIds(
// j,
// value,
// );
// provider.selectedProductIds[j] =
// value.id?.toString() ??
// '';
// provider.updateTotalAmount(
// j,
// );
// }
// },
// buttonStyleData:
// ddtheme.buttonStyleData,
// iconStyleData:
// ddtheme.iconStyleData,
// menuItemStyleData:
// ddtheme.menuItemStyleData,
// dropdownStyleData:
// ddtheme.dropdownStyleData,
// ),
// ),
// ],
// ),
// ),
// const SizedBox(height: 10),
// Row(
// children: [
// Expanded(
// flex: 2,
// child: textControllerWidget(
// context,
// provider
// .editProductPriceControllers[j],
// "Product Price",
// "Enter Product Price",
// (value) =>
// provider.updateTotalAmount(j),
// TextInputType.number,
// false,
// FilteringTextInputFormatter
// .digitsOnly,
// ),
// ),
// ],
// ),
// const SizedBox(height: 10),
// Row(
// children: [
// Expanded(
// flex: 2,
// child: textControllerWidget(
// context,
// provider
// .editQuantityControllers[j],
// "Quantity",
// "Enter Quantity",
// (value) =>
// provider.updateTotalAmount(j),
// TextInputType.number,
// false,
// FilteringTextInputFormatter
// .digitsOnly,
// ),
// ),
// ],
// ),
// const SizedBox(height: 10),
// Row(
// children: [
// Expanded(
// flex: 2,
// child: textControllerWidget(
// context,
// provider
// .editTotalAmountControllers[j],
// "Amount",
// "Total Amount",
// (_) {},
// TextInputType.number,
// true,
// FilteringTextInputFormatter
// .digitsOnly,
// ),
// ),
// ],
// ),
// // IconButton(
// // icon: const Icon(Icons.delete),
// // onPressed: provider.editProductPriceControllers.length > 1
// // ? () => provider.editRemoveRow(j)
// // : null,
// // ),
// ],
// ),
// );
// },
// ),
// ],
],
),
),
...
...
@@ -896,50 +709,6 @@ class _GeneratequotationscreenState extends State<Generatequotationscreen> {
),
),
),
// Expanded(
// child: InkResponse(
// onTap:
// provider.submitLoading
// ? null
// : () {
// //genquotewhatsappbymynum,
// final insertedData = provider.getFormData();
// provider
// .crmLeadDetailsGenerateQuoteSubmitAPIFunction(
// context,
// widget.leadId,
// insertedData,
// "genquotewhatsappbymynum",
// );
// },
// child: Container(
// height: 45,
// alignment: Alignment.center,
// margin: const EdgeInsets.symmetric(
// horizontal: 10,
// vertical: 15,
// ),
// padding: const EdgeInsets.symmetric(
// horizontal: 10,
// vertical: 5,
// ),
// decoration: BoxDecoration(
// // color: AppColors.app_blue,
// borderRadius: BorderRadius.circular(10),
// ),
// child:
// provider.submitLoading
// ? CircularProgressIndicator.adaptive(
// valueColor: AlwaysStoppedAnimation<Color>(
// AppColors.app_blue,
// ),
// )
// : SvgPicture.asset(
// "assets/svg/whatsapp_quote_self.svg",
// ),
// ),
// ),
// ),
],
),
),
...
...
lib/screens/finance/AllPaymentRequesitionListsByModes.dart
View file @
dc88a3f9
...
...
@@ -792,7 +792,8 @@ class _AllpaymentrequesitionlistsbymodesState
provider
.
selectedID
=
value
.
id
!;
provider
.
selectedValue
=
value
.
name
!;
print
(
"hfjkshfg
${provider.selectedID}
"
,
"hfjkshfg"
+
provider
.
selectedID
.
toString
(),
);
}
}
...
...
@@ -898,9 +899,14 @@ class _AllpaymentrequesitionlistsbymodesState
},
);
},
).
whenComplete
(()
{
).
then
((
value
)
{
// This runs only when the bottom sheet is explicitly popped
print
(
"closing Sheet"
);
// Use the original context with mounted check
if
(
context
.
mounted
)
{
WidgetsBinding
.
instance
.
addPostFrameCallback
((
timeStamp
)
{
if
(
context
.
mounted
)
{
var
provider
=
Provider
.
of
<
Requestionlistprovider
>(
context
,
listen:
false
,
...
...
@@ -917,7 +923,9 @@ class _AllpaymentrequesitionlistsbymodesState
""
,
""
,
);
}
});
}
});
}
...
...
lib/screens/finance/FileViewer.dart
View file @
dc88a3f9
...
...
@@ -10,6 +10,7 @@ import 'package:url_launcher/url_launcher.dart';
import
'package:flutter_pdfview/flutter_pdfview.dart'
;
import
'package:http/http.dart'
as
http
;
import
'dart:typed_data'
;
import
'package:photo_view/photo_view.dart'
;
import
'../../Utils/app_colors.dart'
;
...
...
@@ -36,6 +37,11 @@ class _FileviewerState extends State<Fileviewer> {
bool
pullToRefreshEnabled
=
true
;
final
GlobalKey
webViewKey
=
GlobalKey
();
// Zoom control variables
PhotoViewController
_photoViewController
=
PhotoViewController
();
PhotoViewScaleStateController
_scaleStateController
=
PhotoViewScaleStateController
();
String
getFileExtension
(
String
fileName
)
{
print
(
widget
.
fileUrl
);
return
fileName
.
split
(
'.'
).
last
.
toLowerCase
();
...
...
@@ -51,9 +57,9 @@ class _FileviewerState extends State<Fileviewer> {
}
var
Finalurl
;
@override
void
initState
()
{
// loadData();
pullToRefreshController
=
kIsWeb
?
null
...
...
@@ -71,16 +77,32 @@ class _FileviewerState extends State<Fileviewer> {
}
},
);
// print("URL:${widget.url}");
// Initialize photo view controllers
_photoViewController
=
PhotoViewController
();
_scaleStateController
=
PhotoViewScaleStateController
();
super
.
initState
();
}
@override
void
dispose
()
{
_photoViewController
.
dispose
();
_scaleStateController
.
dispose
();
pullToRefreshController
?.
dispose
();
super
.
dispose
();
}
@override
Widget
build
(
BuildContext
context
)
{
return
Scaffold
(
resizeToAvoidBottomInset:
true
,
appBar:
appbarNew
(
context
,
"File Viewer"
,
0xFFFFFFFF
),
body:
SafeArea
(
child:
Center
(
child:
fileWidget
(
context
))),
body:
SafeArea
(
child:
Center
(
child:
fileWidget
(
context
)
),
),
);
}
...
...
@@ -91,23 +113,86 @@ class _FileviewerState extends State<Fileviewer> {
case
'jpeg'
:
case
'png'
:
case
'gif'
:
return
CachedNetworkImage
(
imageUrl:
widget
.
fileUrl
,
placeholder:
(
context
,
url
)
=>
const
Center
(
child:
CircularProgressIndicator
()),
errorWidget:
(
context
,
url
,
error
)
=>
const
Icon
(
Icons
.
error
),
fit:
BoxFit
.
contain
,
);
case
'bmp'
:
case
'webp'
:
return
_buildImageViewer
();
case
'pdf'
:
return
Sf
PdfViewer
.
network
(
widget
.
fileUrl
,
key:
GlobalKey
()
);
return
_build
PdfViewer
(
);
case
'doc'
:
case
'docx'
:
case
'xls'
:
case
'xlsx'
:
return
InAppWebView
(
case
'ppt'
:
case
'pptx'
:
return
_buildDocumentViewer
();
default
:
return
_buildUnsupportedViewer
();
}
}
Widget
_buildImageViewer
()
{
return
PhotoView
(
imageProvider:
CachedNetworkImageProvider
(
widget
.
fileUrl
),
loadingBuilder:
(
context
,
event
)
=>
Center
(
child:
Container
(
width:
40
,
height:
40
,
child:
CircularProgressIndicator
(
value:
event
==
null
?
0
:
event
.
cumulativeBytesLoaded
/
(
event
.
expectedTotalBytes
??
1
),
),
),
),
errorBuilder:
(
context
,
error
,
stackTrace
)
=>
Center
(
child:
Column
(
mainAxisAlignment:
MainAxisAlignment
.
center
,
children:
[
Icon
(
Icons
.
error_outline
,
color:
Colors
.
red
,
size:
50
),
SizedBox
(
height:
10
),
Text
(
'Failed to load image'
,
style:
TextStyle
(
fontSize:
16
,
color:
Colors
.
grey
),
),
],
),
),
backgroundDecoration:
BoxDecoration
(
color:
Colors
.
white
),
minScale:
PhotoViewComputedScale
.
contained
*
0.5
,
maxScale:
PhotoViewComputedScale
.
covered
*
4.0
,
initialScale:
PhotoViewComputedScale
.
contained
,
basePosition:
Alignment
.
center
,
scaleStateController:
_scaleStateController
,
controller:
_photoViewController
,
enableRotation:
true
,
gestureDetectorBehavior:
HitTestBehavior
.
deferToChild
,
filterQuality:
FilterQuality
.
high
,
);
}
Widget
_buildPdfViewer
()
{
return
SfPdfViewer
.
network
(
widget
.
fileUrl
,
key:
GlobalKey
(),
canShowScrollHead:
true
,
canShowPaginationDialog:
true
,
pageLayoutMode:
PdfPageLayoutMode
.
single
,
interactionMode:
PdfInteractionMode
.
pan
,
enableDoubleTapZooming:
true
,
enableTextSelection:
true
,
onZoomLevelChanged:
(
PdfZoomDetails
details
)
{
// Use the correct property name
//print('Zoom level changed: ${details.zoomLevel}');
},
);
}
Widget
_buildDocumentViewer
()
{
return
Stack
(
children:
[
InAppWebView
(
key:
webViewKey
,
initialUrlRequest:
URLRequest
(
url:
WebUri
(
widget
.
fileUrl
)),
androidOnGeolocationPermissionsShowPrompt:
(
InAppWebViewController
controller
,
...
...
@@ -120,22 +205,36 @@ class _FileviewerState extends State<Fileviewer> {
);
},
initialOptions:
InAppWebViewGroupOptions
(
crossPlatform:
InAppWebViewOptions
(
useShouldOverrideUrlLoading:
true
,
mediaPlaybackRequiresUserGesture:
false
,
javaScriptEnabled:
true
,
clearCache:
true
,
supportZoom:
true
,
),
android:
AndroidInAppWebViewOptions
(
useWideViewPort:
true
,
loadWithOverviewMode:
true
,
allowContentAccess:
true
,
geolocationEnabled:
true
,
allowFileAccess:
true
,
databaseEnabled:
true
,
// Enables the WebView database
domStorageEnabled:
true
,
// Enables DOM storage
builtInZoomControls:
true
,
// Enables the built-in zoom controls
displayZoomControls:
false
,
// Disables displaying zoom controls
safeBrowsingEnabled:
true
,
// Enables Safe Browsing
databaseEnabled:
true
,
domStorageEnabled:
true
,
builtInZoomControls:
true
,
displayZoomControls:
false
,
safeBrowsingEnabled:
true
,
clearSessionCache:
true
,
supportMultipleWindows:
false
,
),
ios:
IOSInAppWebViewOptions
(
allowsInlineMediaPlayback:
true
,
allowsAirPlayForMediaPlayback:
true
,
allowsPictureInPictureMediaPlayback:
true
,
allowsBackForwardNavigationGestures:
true
,
allowsLinkPreview:
true
,
isFraudulentWebsiteWarningEnabled:
true
,
),
ios:
IOSInAppWebViewOptions
(
allowsInlineMediaPlayback:
true
),
),
androidOnPermissionRequest:
(
InAppWebViewController
controller
,
String
origin
,
...
...
@@ -152,18 +251,29 @@ class _FileviewerState extends State<Fileviewer> {
},
pullToRefreshController:
pullToRefreshController
,
onLoadStart:
(
controller
,
url
)
{
return
setState
(()
{
setState
(()
{
isLoading
=
true
;
});
},
onLoadStop:
(
controller
,
url
)
{
pullToRefreshController
?.
endRefreshing
();
return
setState
(()
{
setState
(()
{
isLoading
=
false
;
});
// Enable zooming in WebView
controller
.
evaluateJavascript
(
source
:
"""
var meta = document.createElement('meta');
meta.name = 'viewport';
meta.content = 'width=device-width, initial-scale=1.0, maximum-scale=4.0, user-scalable=yes';
document.getElementsByTagName('head')[0].appendChild(meta);
"""
);
},
onReceivedError:
(
controller
,
request
,
error
)
{
pullToRefreshController
?.
endRefreshing
();
setState
(()
{
isLoading
=
false
;
});
},
onProgressChanged:
(
controller
,
progress
)
{
if
(
progress
==
100
)
{
...
...
@@ -172,21 +282,101 @@ class _FileviewerState extends State<Fileviewer> {
},
onConsoleMessage:
(
controller
,
consoleMessage
)
{
if
(
kDebugMode
)
{
debugPrint
(
"consoleMessage
$
consoleMessage
"
);
debugPrint
(
"consoleMessage
:
${
consoleMessage
.message}
"
);
}
debugPrint
(
"JavaScript console message:
${consoleMessage.message}
"
);
},
),
// Loading indicator for documents
if
(
isLoading
)
Positioned
.
fill
(
child:
Container
(
color:
Colors
.
black
.
withOpacity
(
0.3
),
child:
Center
(
child:
Container
(
padding:
EdgeInsets
.
all
(
20
),
decoration:
BoxDecoration
(
color:
Colors
.
white
,
borderRadius:
BorderRadius
.
circular
(
10
),
boxShadow:
[
BoxShadow
(
color:
Colors
.
black26
,
blurRadius:
10
,
),
],
),
child:
Column
(
mainAxisSize:
MainAxisSize
.
min
,
children:
[
CircularProgressIndicator
(
valueColor:
AlwaysStoppedAnimation
<
Color
>(
AppColors
.
app_blue
),
),
SizedBox
(
height:
10
),
Text
(
'Loading Document...'
,
style:
TextStyle
(
fontSize:
14
,
color:
Colors
.
grey
[
700
],
),
),
],
),
),
),
),
),
],
);
default
:
return
Container
();
}
Widget
_buildUnsupportedViewer
()
{
return
Center
(
child:
Column
(
mainAxisAlignment:
MainAxisAlignment
.
center
,
children:
[
Icon
(
Icons
.
insert_drive_file
,
size:
64
,
color:
Colors
.
grey
[
400
],
),
SizedBox
(
height:
16
),
Text
(
'Unsupported File Format'
,
style:
TextStyle
(
fontSize:
18
,
fontWeight:
FontWeight
.
w600
,
color:
Colors
.
grey
[
600
],
),
),
SizedBox
(
height:
8
),
Text
(
'Format:
${getFileExtension(widget.fileName).toUpperCase()}
'
,
style:
TextStyle
(
fontSize:
14
,
color:
Colors
.
grey
[
500
],
),
),
SizedBox
(
height:
16
),
ElevatedButton
.
icon
(
onPressed:
()
{
_launchUrl
(
widget
.
fileUrl
);
},
icon:
Icon
(
Icons
.
open_in_new
),
label:
Text
(
'Open in External App'
),
style:
ElevatedButton
.
styleFrom
(
backgroundColor:
AppColors
.
app_blue
,
foregroundColor:
Colors
.
white
,
),
),
],
),
);
}
Future
<
Uint8List
?>
_loadPdf
(
String
url
)
async
{
try
{
final
response
=
await
http
.
get
(
Uri
.
parse
(
url
));
if
(
response
.
statusCode
==
200
)
{
print
(
response
.
bodyBytes
);
return
response
.
bodyBytes
;
}
}
catch
(
e
)
{
...
...
lib/screens/finance/PaymentRequestionListDetails.dart
View file @
dc88a3f9
...
...
@@ -1446,7 +1446,8 @@ class _PaymentrequestionlistdetailsState
provider
.
selectedID
=
value
.
id
!;
provider
.
selectedValue
=
value
.
name
!;
print
(
"hfjkshfg
${provider.selectedID}
"
,
"hfjkshfg"
+
provider
.
selectedID
.
toString
(),
);
}
}
...
...
@@ -1511,6 +1512,12 @@ class _PaymentrequestionlistdetailsState
),
InkWell
(
onTap:
()
{
print
(
"🖱️ === SUBMIT BUTTON TAPPED ==="
);
print
(
"📋 Mode:
${widget.mode}
"
);
print
(
"📋 Payment ID:
$paymentID
"
);
print
(
"📋 Approved Amount:
${provider.approvedAmount.text}
"
);
print
(
"📋 Remarks:
${remarks.text}
"
);
print
(
"📋 Selected Account ID:
${provider.selectedID}
"
);
provider
.
paymentrequisitionApproveSubmitAPIFunction
(
context
,
...
...
lib/screens/hrm/AdvanceListScreen.dart
0 → 100644
View file @
dc88a3f9
import
'package:flutter/material.dart'
;
import
'package:provider/provider.dart'
;
import
'../../Notifiers/HomeScreenNotifier.dart'
;
import
'../../Models/hrmModels/advanceListResponse.dart'
;
import
'package:intl/intl.dart'
;
import
'package:flutter_svg/svg.dart'
;
import
'../../Notifiers/hrmProvider/advanceProvider.dart'
;
import
'../../Utils/app_colors.dart'
;
class
AdvanceListScreen
extends
StatefulWidget
{
const
AdvanceListScreen
({
super
.
key
});
@override
State
<
AdvanceListScreen
>
createState
()
=>
_AdvanceListScreenState
();
}
class
_AdvanceListScreenState
extends
State
<
AdvanceListScreen
>
{
final
ScrollController
_scrollController
=
ScrollController
();
@override
void
initState
()
{
super
.
initState
();
final
provider
=
Provider
.
of
<
AdvanceListProvider
>(
context
,
listen:
false
);
final
homeProvider
=
Provider
.
of
<
HomescreenNotifier
>(
context
,
listen:
false
);
WidgetsBinding
.
instance
.
addPostFrameCallback
((
_
)
{
provider
.
fetchAdvanceList
(
context
,
homeProvider
.
session
,
homeProvider
.
empId
);
});
_scrollController
.
addListener
(()
{
if
(
_scrollController
.
position
.
pixels
>=
_scrollController
.
position
.
maxScrollExtent
-
200
)
{
provider
.
loadMoreAdvanceList
(
context
,
homeProvider
.
session
,
homeProvider
.
empId
);
}
});
}
@override
Widget
build
(
BuildContext
context
)
{
final
double
screenWidth
=
MediaQuery
.
of
(
context
).
size
.
width
;
final
double
screenHeight
=
MediaQuery
.
of
(
context
).
size
.
height
;
final
bool
isSmallScreen
=
screenWidth
<
360
;
final
bool
isLargeScreen
=
screenWidth
>
600
;
return
Scaffold
(
appBar:
AppBar
(
automaticallyImplyLeading:
false
,
backgroundColor:
Colors
.
white
,
title:
Row
(
children:
[
InkResponse
(
onTap:
()
=>
Navigator
.
pop
(
context
,
true
),
child:
SvgPicture
.
asset
(
"assets/svg/appbar_back_button.svg"
,
height:
isSmallScreen
?
22
:
25
,
),
),
SizedBox
(
width:
isSmallScreen
?
8
:
10
),
Text
(
"Advance List"
,
style:
TextStyle
(
fontSize:
isSmallScreen
?
16
:
18
,
fontFamily:
"Plus Jakarta Sans"
,
fontWeight:
FontWeight
.
w600
,
color:
Colors
.
black87
,
),
),
],
),
),
backgroundColor:
AppColors
.
scaffold_bg_color
,
body:
Consumer
<
AdvanceListProvider
>(
builder:
(
context
,
provider
,
_
)
{
if
(
provider
.
isLoading
&&
provider
.
advanceList
.
isEmpty
)
{
return
const
Center
(
child:
CircularProgressIndicator
());
}
if
(
provider
.
errorMessage
!=
null
)
{
return
Padding
(
padding:
EdgeInsets
.
symmetric
(
horizontal:
isSmallScreen
?
16
:
20
),
child:
Center
(
child:
Text
(
provider
.
errorMessage
!,
style:
TextStyle
(
color:
Colors
.
red
,
fontSize:
isSmallScreen
?
14
:
16
,
fontFamily:
"Plus Jakarta Sans"
,
),
textAlign:
TextAlign
.
center
,
),
),
);
}
if
(
provider
.
advanceList
.
isEmpty
)
{
return
Padding
(
padding:
EdgeInsets
.
symmetric
(
horizontal:
isSmallScreen
?
16
:
20
),
child:
Center
(
child:
Text
(
"No records found."
,
style:
TextStyle
(
fontSize:
isSmallScreen
?
14
:
16
,
fontFamily:
"Plus Jakarta Sans"
,
color:
AppColors
.
grey_semi
,
),
),
),
);
}
return
ListView
.
builder
(
controller:
_scrollController
,
padding:
EdgeInsets
.
all
(
isSmallScreen
?
8
:
isLargeScreen
?
16
:
12
),
itemCount:
provider
.
advanceList
.
length
+
(
provider
.
isLoading
?
1
:
0
),
// for pagination loader
itemBuilder:
(
context
,
index
)
{
if
(
index
==
provider
.
advanceList
.
length
)
{
return
Padding
(
padding:
EdgeInsets
.
all
(
isSmallScreen
?
12.0
:
16.0
),
child:
const
Center
(
child:
CircularProgressIndicator
()),
);
}
AdvanceList
item
=
provider
.
advanceList
[
index
];
return
_buildAdvanceCard
(
item
,
screenWidth
);
},
);
},
),
);
}
Widget
_buildAdvanceCard
(
AdvanceList
item
,
double
screenWidth
)
{
final
bool
isSmallScreen
=
screenWidth
<
360
;
final
bool
isLargeScreen
=
screenWidth
>
600
;
final
date
=
item
.
createdDatetime
!=
null
?
_formatDate
(
item
.
createdDatetime
!)
:
"-"
;
return
Card
(
shape:
RoundedRectangleBorder
(
borderRadius:
BorderRadius
.
circular
(
isSmallScreen
?
12
:
16
)),
margin:
EdgeInsets
.
symmetric
(
vertical:
isSmallScreen
?
5
:
7
,
horizontal:
isLargeScreen
?
4
:
0
,
),
elevation:
0
,
child:
Padding
(
padding:
EdgeInsets
.
symmetric
(
horizontal:
isSmallScreen
?
12
:
isLargeScreen
?
18
:
14
,
vertical:
isSmallScreen
?
10
:
isLargeScreen
?
14
:
12
,
),
child:
Row
(
children:
[
// Circular Avatar - Responsive size
CircleAvatar
(
backgroundColor:
_getAvatarColor
(
item
.
type
),
radius:
isSmallScreen
?
18
:
isLargeScreen
?
26
:
22
,
child:
Text
(
(
item
.
narration
?.
isNotEmpty
==
true
)
?
item
.
type
![
0
].
toUpperCase
()
:
"?"
,
style:
TextStyle
(
color:
_getAvatarTxtColor
(
item
.
type
),
fontWeight:
FontWeight
.
bold
,
fontSize:
isSmallScreen
?
12
:
isLargeScreen
?
16
:
14
,
),
),
),
SizedBox
(
width:
isSmallScreen
?
12
:
isLargeScreen
?
16
:
14
),
// Title + Subtitle
Expanded
(
child:
Column
(
crossAxisAlignment:
CrossAxisAlignment
.
start
,
children:
[
Text
(
item
.
narration
??
"No Title"
,
style:
TextStyle
(
fontFamily:
"JakartaRegular"
,
fontSize:
isSmallScreen
?
13
:
isLargeScreen
?
16
:
14
,
color:
AppColors
.
semi_black
,
),
maxLines:
2
,
overflow:
TextOverflow
.
ellipsis
,
),
SizedBox
(
height:
isSmallScreen
?
2
:
4
),
Text
(
date
,
style:
TextStyle
(
fontFamily:
"JakartaRegular"
,
fontSize:
isSmallScreen
?
12
:
isLargeScreen
?
14
:
13
,
color:
AppColors
.
grey_semi
,
),
),
],
),
),
SizedBox
(
width:
isSmallScreen
?
8
:
isLargeScreen
?
12
:
10
),
// Right side amounts
Column
(
crossAxisAlignment:
CrossAxisAlignment
.
end
,
children:
[
if
(
item
.
issuedAmount
!=
"₹ 0.00"
)
Text
(
"
${item.issuedAmount ?? "0"}
"
,
style:
TextStyle
(
fontFamily:
"JakartaMedium"
,
fontSize:
isSmallScreen
?
13
:
isLargeScreen
?
16
:
14
,
color:
const
Color
(
0xff1487c9
),
),
textAlign:
TextAlign
.
end
,
),
if
(
item
.
deductedAmount
!=
"₹ 0.00"
)
SizedBox
(
height:
isSmallScreen
?
1
:
2
),
if
(
item
.
deductedAmount
!=
"₹ 0.00"
)
Text
(
"-
${item.deductedAmount ?? "0"}
"
,
style:
TextStyle
(
fontFamily:
"JakartaMedium"
,
fontSize:
isSmallScreen
?
13
:
isLargeScreen
?
16
:
14
,
color:
AppColors
.
red
,
),
textAlign:
TextAlign
.
end
,
),
],
),
],
),
),
);
}
String
_formatDate
(
String
dateStr
)
{
try
{
final
date
=
DateTime
.
parse
(
dateStr
);
return
DateFormat
(
"dd MMM yy"
).
format
(
date
);
}
catch
(
_
)
{
return
dateStr
;
}
}
@override
void
dispose
()
{
_scrollController
.
dispose
();
super
.
dispose
();
}
/// Avatar color generator
Color
_getAvatarColor
(
value
)
{
var
color
=
AppColors
.
approved_bg_color
;
switch
(
value
)
{
case
'issued'
:
return
AppColors
.
requested_bg_color
;
case
'received'
:
return
AppColors
.
approved_bg_color
;
}
return
color
;
}
Color
_getAvatarTxtColor
(
value
)
{
var
color
=
AppColors
.
approved_text_color
;
switch
(
value
)
{
case
'issued'
:
return
AppColors
.
requested_text_color
;
case
'received'
:
return
AppColors
.
approved_text_color
;
}
return
color
;
}
String
getText
(
value
)
{
switch
(
value
)
{
case
'issued'
:
return
"I"
;
case
'received'
:
return
"R"
;
default
:
return
"-"
;
}
}
}
\ No newline at end of file
lib/screens/hrm/CasualLeaveHistoryScreen.dart
0 → 100644
View file @
dc88a3f9
import
'package:flutter/material.dart'
;
import
'package:flutter_svg/flutter_svg.dart'
;
import
'package:provider/provider.dart'
;
import
'../../Notifiers/hrmProvider/CasualLeaveHistoryProvider.dart'
;
import
'../../Utils/app_colors.dart'
;
class
CasualLeaveHistoryScreen
extends
StatefulWidget
{
const
CasualLeaveHistoryScreen
({
super
.
key
});
@override
State
<
CasualLeaveHistoryScreen
>
createState
()
=>
_CasualLeaveHistoryScreenState
();
}
class
_CasualLeaveHistoryScreenState
extends
State
<
CasualLeaveHistoryScreen
>
{
@override
void
initState
()
{
super
.
initState
();
// Fetch data once when the screen loads
Future
.
delayed
(
Duration
.
zero
,
()
{
final
provider
=
Provider
.
of
<
CasualLeaveHistoryProvider
>(
context
,
listen:
false
);
provider
.
fetchCasualLeaveHistory
(
context
);
});
}
@override
Widget
build
(
BuildContext
context
)
{
final
double
screenWidth
=
MediaQuery
.
of
(
context
).
size
.
width
;
final
double
screenHeight
=
MediaQuery
.
of
(
context
).
size
.
height
;
final
bool
isSmallScreen
=
screenWidth
<
360
;
final
bool
isLargeScreen
=
screenWidth
>
600
;
final
bool
isTablet
=
screenWidth
>
768
;
return
Scaffold
(
backgroundColor:
AppColors
.
scaffold_bg_color
,
appBar:
AppBar
(
automaticallyImplyLeading:
false
,
backgroundColor:
Colors
.
white
,
title:
Row
(
children:
[
InkResponse
(
onTap:
()
=>
Navigator
.
pop
(
context
,
true
),
child:
SvgPicture
.
asset
(
"assets/svg/appbar_back_button.svg"
,
height:
isSmallScreen
?
22
:
isTablet
?
28
:
25
,
),
),
SizedBox
(
width:
isSmallScreen
?
8
:
isTablet
?
12
:
10
),
Text
(
"Casual Leave History"
,
style:
TextStyle
(
fontSize:
isSmallScreen
?
16
:
isTablet
?
20
:
18
,
fontFamily:
"Plus Jakarta Sans"
,
fontWeight:
FontWeight
.
w600
,
color:
Colors
.
black87
,
),
),
],
),
),
body:
Consumer
<
CasualLeaveHistoryProvider
>(
builder:
(
context
,
provider
,
_
)
{
if
(
provider
.
isLoading
)
{
return
const
Center
(
child:
CircularProgressIndicator
());
}
if
(
provider
.
errorMessage
!=
null
)
{
return
Padding
(
padding:
EdgeInsets
.
symmetric
(
horizontal:
isSmallScreen
?
16
:
20
),
child:
Center
(
child:
Text
(
provider
.
errorMessage
!,
style:
TextStyle
(
color:
Colors
.
white
,
fontSize:
isSmallScreen
?
14
:
16
,
fontFamily:
"Plus Jakarta Sans"
,
),
textAlign:
TextAlign
.
center
,
),
),
);
}
if
(
provider
.
casualLeaveHistoryList
.
isEmpty
)
{
return
Padding
(
padding:
EdgeInsets
.
symmetric
(
horizontal:
isSmallScreen
?
16
:
20
),
child:
Center
(
child:
Text
(
"No leave history found"
,
style:
TextStyle
(
color:
Colors
.
white
,
fontSize:
isSmallScreen
?
14
:
16
,
fontFamily:
"Plus Jakarta Sans"
,
),
),
),
);
}
return
ListView
.
builder
(
padding:
EdgeInsets
.
all
(
isSmallScreen
?
8
:
isTablet
?
16
:
12
),
itemCount:
provider
.
casualLeaveHistoryList
.
length
,
itemBuilder:
(
context
,
index
)
{
final
item
=
provider
.
casualLeaveHistoryList
[
index
];
return
Padding
(
padding:
EdgeInsets
.
symmetric
(
vertical:
isSmallScreen
?
4
:
isTablet
?
8
:
6
,
),
child:
Container
(
decoration:
BoxDecoration
(
color:
Colors
.
white
,
borderRadius:
BorderRadius
.
circular
(
isSmallScreen
?
12
:
isTablet
?
20
:
16
,
),
),
padding:
EdgeInsets
.
symmetric
(
horizontal:
isSmallScreen
?
12
:
isTablet
?
18
:
14
,
vertical:
isSmallScreen
?
8
:
isTablet
?
14
:
10
,
),
child:
Row
(
children:
[
// --- Avatar Circle ---
Container
(
height:
isSmallScreen
?
40
:
isTablet
?
54
:
46
,
width:
isSmallScreen
?
40
:
isTablet
?
54
:
46
,
decoration:
BoxDecoration
(
color:
_getAvatarColor
(
item
.
type
),
shape:
BoxShape
.
circle
,
),
child:
Center
(
child:
Text
(
getText
(
item
.
type
),
style:
TextStyle
(
fontSize:
isSmallScreen
?
13
:
isTablet
?
17
:
15
,
fontFamily:
"Plus Jakarta Sans"
,
fontWeight:
FontWeight
.
w500
,
color:
_getAvatarTxtColor
(
item
.
type
),
),
),
),
),
SizedBox
(
width:
isSmallScreen
?
10
:
isTablet
?
16
:
12
),
// --- Main Content ---
Expanded
(
child:
Column
(
crossAxisAlignment:
CrossAxisAlignment
.
start
,
children:
[
Text
(
item
.
des
??
"No Description"
,
style:
TextStyle
(
fontFamily:
"JakartaRegular"
,
fontSize:
isSmallScreen
?
13
:
isTablet
?
16
:
14
,
color:
AppColors
.
semi_black
,
height:
1.2
,
),
maxLines:
2
,
overflow:
TextOverflow
.
ellipsis
,
),
SizedBox
(
height:
isSmallScreen
?
2
:
isTablet
?
6
:
4
),
Text
(
item
.
year
??
""
,
style:
TextStyle
(
fontFamily:
"JakartaRegular"
,
fontSize:
isSmallScreen
?
12
:
isTablet
?
14
:
13
,
color:
AppColors
.
grey_semi
,
),
),
],
),
),
// --- Duration Badge (like "1 Day") ---
Container
(
decoration:
BoxDecoration
(
color:
Colors
.
blue
.
shade50
,
borderRadius:
BorderRadius
.
circular
(
isSmallScreen
?
16
:
isTablet
?
24
:
20
,
),
),
padding:
EdgeInsets
.
symmetric
(
horizontal:
isSmallScreen
?
12
:
isTablet
?
16
:
14
,
vertical:
isSmallScreen
?
4
:
isTablet
?
8
:
6
,
),
child:
Text
(
"
${item.cnt ?? '0'}
Day
${(item.cnt ?? '0') == '1' ? '' : 's'}
"
,
style:
TextStyle
(
fontFamily:
"JakartaMedium"
,
fontSize:
isSmallScreen
?
12
:
isTablet
?
15
:
14
,
color:
Color
(
0xff1487c9
),
),
),
),
],
),
),
);
},
);
},
),
);
}
/// Avatar color generator
Color
_getAvatarColor
(
value
)
{
var
color
=
AppColors
.
approved_bg_color
;
switch
(
value
)
{
case
'minus'
:
return
AppColors
.
rejected_bg_color
;
case
'plus'
:
return
AppColors
.
approved_bg_color
;
}
return
color
;
}
Color
_getAvatarTxtColor
(
value
)
{
var
color
=
AppColors
.
approved_text_color
;
switch
(
value
)
{
case
'minus'
:
return
AppColors
.
rejected_text_color
;
case
'plus'
:
return
AppColors
.
approved_text_color
;
}
return
color
;
}
String
getText
(
value
)
{
switch
(
value
)
{
case
'minus'
:
return
"M"
;
case
'plus'
:
return
"P"
;
default
:
return
"-"
;
}
}
}
\ No newline at end of file
lib/screens/hrm/HrmDashboardScreen.dart
View file @
dc88a3f9
...
...
@@ -3,6 +3,8 @@ import 'package:flutter_svg/svg.dart';
import
'package:generp/screens/hrm/Attendancelist.dart'
;
import
'package:provider/provider.dart'
;
import
'../../Utils/app_colors.dart'
;
import
'AdvanceListScreen.dart'
;
import
'CasualLeaveHistoryScreen.dart'
;
import
'LeaveApplicationScreen.dart'
;
import
'TourExpensesListScreen.dart'
;
import
'RewardListScreen.dart'
;
...
...
@@ -24,6 +26,8 @@ class _HrmdashboardScreenState extends State<HrmdashboardScreen> {
"Tour Bill List"
,
"Rewards List"
,
"Attendance Request List"
,
"Advance List"
,
"Casual Leave List"
];
@override
...
...
@@ -215,7 +219,7 @@ class _HrmdashboardScreenState extends State<HrmdashboardScreen> {
crossAxisCount:
(
constraints
.
maxWidth
/
180
)
.
floor
()
.
clamp
(
2
,
4
),
.
clamp
(
2
,
6
),
crossAxisSpacing:
1
,
mainAxisSpacing:
2
,
childAspectRatio:
1.8
,
...
...
@@ -224,7 +228,7 @@ class _HrmdashboardScreenState extends State<HrmdashboardScreen> {
final
page
=
pages
[
index
];
return
_buildTile
(
label:
page
.
pageName
??
""
,
label:
page
.
pageName
??
""
,
//in page number there is 6 items comming from serever it showing only four
subtitle:
_getSubtitle
(
page
.
pageName
??
""
,
),
...
...
@@ -244,6 +248,11 @@ class _HrmdashboardScreenState extends State<HrmdashboardScreen> {
);
},
),
////////////
SizedBox
(
height:
40
,)
],
),
],
...
...
@@ -355,6 +364,10 @@ class _HrmdashboardScreenState extends State<HrmdashboardScreen> {
return
""
;
case
"Team Attendance Approval"
:
return
""
;
case
"Advance List"
:
return
"Advance Payment"
;
case
"Casual Leave List"
:
return
"Track Casual Leave"
;
default
:
return
""
;
}
...
...
@@ -375,6 +388,10 @@ class _HrmdashboardScreenState extends State<HrmdashboardScreen> {
return
"assets/svg/hrm/logout_ic.svg"
;
case
"Team Attendance Approval"
:
return
"assets/svg/hrm/check_ic.svg"
;
case
"Advance List"
:
return
"assets/svg/hrm/advance_list_ic.svg"
;
case
"Casual Leave List"
:
return
"assets/svg/hrm/casual_leave_history_ic.svg"
;
default
:
return
"assets/svg/hrm/groupIc.svg"
;
}
...
...
@@ -432,6 +449,24 @@ class _HrmdashboardScreenState extends State<HrmdashboardScreen> {
),
);
break
;
case
"Advance List"
:
Navigator
.
push
(
context
,
MaterialPageRoute
(
builder:
(
context
)
=>
AdvanceListScreen
(),
),
);
break
;
case
"Casual Leave List"
:
Navigator
.
push
(
context
,
MaterialPageRoute
(
builder:
(
context
)
=>
CasualLeaveHistoryScreen
(),
),
);
break
;
}
}
}
lib/screens/notifierExports.dart
View file @
dc88a3f9
...
...
@@ -65,6 +65,6 @@ export 'package:generp/Notifiers/hrmProvider/tourExpensesDetailsProvider.dart';
export
'package:generp/Notifiers/hrmProvider/rewardListProvider.dart'
;
export
'package:generp/Notifiers/hrmProvider/LeaveApplicationListProvider.dart'
;
export
'package:generp/Notifiers/hrmProvider/LeaveApplicationDetailsProvider.dart'
;
export
'package:generp/Notifiers/hrmProvider/CasualLeaveHistoryProvider.dart'
;
export
'package:generp/Notifiers/hrmprovider/orgprovider.dart'
;
lib/screens/order/addOrder.dart
View file @
dc88a3f9
...
...
@@ -25,8 +25,14 @@ import 'package:dropdown_search/dropdown_search.dart';
class
AddorderScreen
extends
StatefulWidget
{
final
pageTitleName
;
final
mode
;
final
leadId
;
final
feedback
;
final
followupType
;
final
inTime
;
final
loc
;
const
AddorderScreen
({
super
.
key
,
this
.
pageTitleName
,
this
.
mode
});
const
AddorderScreen
({
super
.
key
,
this
.
pageTitleName
,
this
.
mode
,
this
.
leadId
,
this
.
feedback
,
this
.
followupType
,
this
.
inTime
,
this
.
loc
});
@override
State
<
AddorderScreen
>
createState
()
=>
_AddorderScreenState
();
...
...
@@ -45,30 +51,99 @@ class _AddorderScreenState extends State<AddorderScreen> {
@override
void
initState
()
{
// TODO: implement initState
super
.
initState
();
_connectivity
.
initialise
();
_connectivity
.
myStream
.
listen
((
source
)
{
setState
(()
=>
_source
=
source
);
});
WidgetsBinding
.
instance
.
addPostFrameCallback
((
timeStamp
)
{
var
provider
=
Provider
.
of
<
Addorderprovider
>(
context
,
listen:
false
);
WidgetsBinding
.
instance
.
addPostFrameCallback
((
_
)
async
{
final
provider
=
Provider
.
of
<
Addorderprovider
>(
context
,
listen:
false
);
final
homeProvider
=
Provider
.
of
<
HomescreenNotifier
>(
context
,
listen:
false
);
if
(
provider
.
dateNow
==
null
)
{
provider
.
setDate
(
DateTime
.
now
());
}
provider
.
getLocationPermission
(
context
);
provider
.
getCurrentLocation
();
provider
.
ordersAddOrderAPIViewFunction
(
context
,
widget
.
mode
);
provider
.
ordersAddOrderSelectAccountAPIFunction
(
// fetch select account API
await
provider
.
ordersAddOrderSelectAccountAPIFunction
(
context
,
widget
.
mode
,
provider
.
selectedAccountID
,
''
,
);
});
if
(
widget
.
pageTitleName
!=
"Add Order"
)
{
provider
.
ordersAddOrderAPIViewFunction
(
context
,
widget
.
mode
,
""
,
""
,
""
,
""
,
""
,
);
}
if
(
widget
.
pageTitleName
==
"Add Order"
)
{
await
provider
.
fetchAddOrderViewData
(
context
,
homeProvider
.
empId
,
homeProvider
.
session
,
widget
.
mode
,
widget
.
leadId
,
widget
.
feedback
,
widget
.
followupType
,
widget
.
inTime
,
widget
.
loc
,
);
debugPrint
(
" fetchAddOrderViewData finished"
);
debugPrint
(
"Assign data to all fields##################################"
);
final
account
=
provider
.
accountDetails
;
if
(
account
!=
null
)
{
await
provider
.
ordersAddOrderSelectAccountAPIFunction
(
context
,
widget
.
mode
,
account
.
id
,
""
,
);
// provider.getDistrictAPI(context, account.district);
// provider.getSubLocationAPI(context, account.subLocality);
provider
.
ordersAddOrderAccountDetailsAPIFunction
(
context
,
account
.
id
);
provider
.
selectedAccountID
=
account
.
id
;
provider
.
selectedAccountName
=
account
.
name
;
provider
.
selectedBillingStateID
=
account
.
state
;
// Fill text controllers
provider
.
billingNameController
.
text
=
account
.
name
??
""
;
provider
.
billingAddressController
.
text
=
account
.
address
??
""
;
provider
.
billingPincodeController
.
text
=
account
.
pincode
??
""
;
provider
.
orderReceivedDateController
.
text
=
account
.
date
??
""
;
provider
.
billingStateSearchController
.
text
=
account
.
state
!;
provider
.
selecetdBillingStates
=
"account.state"
as
States
?;
debugPrint
(
"Auto filled"
);
provider
.
accountList
.
first
=
account
.
name
as
AccountList
;
// provider.billingDistrictSearchController.text = district as String;
// provider.selectedBillingDistricts = district as Districts?;
//
// provider.billingSubLocSearchController.text = account.subLocality!;
// provider.selectedBillingSubLocations = account.subLocality as SubLocations?;
provider
.
dropDownSearchController
.
text
=
account
.
name
!;
provider
.
selectedAccountName
=
account
.
name
;
provider
.
notifyListeners
();
}
}
});
}
@override
void
dispose
()
{
focusNodes
.
map
((
e
)
=>
e
.
dispose
());
...
...
@@ -152,6 +227,7 @@ class _AddorderScreenState extends State<AddorderScreen> {
Widget
_scaffold
(
BuildContext
context
)
{
return
Consumer
<
Addorderprovider
>(
builder:
(
context
,
provider
,
child
)
{
return
WillPopScope
(
child:
SafeArea
(
top:
false
,
...
...
@@ -295,13 +371,14 @@ class _AddorderScreenState extends State<AddorderScreen> {
if
(
value
!=
null
)
{
print
(
'Selected account:
${value.text}
'
);
provider
.
selectedAccountList
=
(
value
);
provider
.
selectedAccountID
=
value
.
id
!;
provider
.
selectedAccountName
=
value
.
text
!;
provider
.
selectedAccountID
=
value
!
.
id
!;
provider
.
selectedAccountName
=
value
!
.
text
!;
provider
.
ordersAddOrderAccountDetailsAPIFunction
(
context
,
value
.
id
,
);
}
},
selectedItem:
provider
.
selectedAccountList
,
...
...
@@ -351,6 +428,7 @@ class _AddorderScreenState extends State<AddorderScreen> {
// },
),
if
(
provider
.
selectAccountError
!=
null
)
...[
errorWidget
(
context
,
...
...
@@ -1150,7 +1228,8 @@ class _AddorderScreenState extends State<AddorderScreen> {
.
isNotEmpty
?
provider
.
selectedDispatchDistricts
!=
null
?
provider
.
dispatchDistricts
.
firstWhere
(
?
provider
.
dispatchDistricts
.
firstWhere
(
(
ord
)
=>
ord
.
id
==
provider
...
...
@@ -1307,7 +1386,9 @@ class _AddorderScreenState extends State<AddorderScreen> {
.
isNotEmpty
?
provider
.
selectedDispatchSubLocations
!=
null
?
provider
.
dispatchSubLocations
.
firstWhere
(
?
provider
.
dispatchSubLocations
.
firstWhere
(
(
ord
)
=>
ord
.
id
==
provider
...
...
@@ -1675,11 +1756,11 @@ class _AddorderScreenState extends State<AddorderScreen> {
scrollbarTheme:
ScrollbarThemeData
(
radius:
const
Radius
.
circular
(
15
),
thickness:
Widget
StateProperty
.
all
<
double
>(
6
,
),
Material
StateProperty
.
all
<
double
>(
6
),
thumbVisibility:
Widget
StateProperty
.
all
<
bool
>(
Material
StateProperty
.
all
<
bool
>(
true
,
),
),
...
...
@@ -1896,9 +1977,9 @@ class _AddorderScreenState extends State<AddorderScreen> {
if
(
value
!=
null
)
{
print
(
'Selected account:
${value.text}
'
);
provider
.
selectedTpcAgent
=
(
value
);
provider
.
selectedTpcAgentID
=
value
.
id
!;
provider
.
selectedTpcAgentID
=
value
!
.
id
!;
provider
.
selectedTpcAgentValue
=
value
.
text
!;
value
!
.
text
!;
}
},
selectedItem:
provider
.
selectedTpcAgent
,
...
...
@@ -2150,8 +2231,7 @@ class _AddorderScreenState extends State<AddorderScreen> {
widget
.
mode
,
provider
.
selectedEmployeeID
,
provider
.
selectedAccountID
,
provider
.
selectedDispatchStateID
,
provider
.
selectedDispatchStateID
,
provider
.
selectedDispatchDistrictId
,
provider
...
...
@@ -2496,7 +2576,9 @@ class _AddorderScreenState extends State<AddorderScreen> {
provider
.
selectedAccountName
=
provider
.
accountList
[
index
].
text
!;
print
(
"hfjkshfg
${provider.selectedAccountID}
"
,
"hfjkshfg"
+
provider
.
selectedAccountID
.
toString
(),
);
provider
.
dropDownSearchController
.
text
=
provider
.
accountList
[
index
].
text
!;
...
...
@@ -2637,7 +2719,7 @@ class _AddorderScreenState extends State<AddorderScreen> {
null
,
TextInputAction
.
done
,
),
if
(
provider
.
billingNameError
!=
null
)
if
(
provider
.
billingNameError
!=
null
)
errorWidget
(
context
,
provider
.
billingNameError
),
TextWidget
(
context
,
"Billing State"
),
//dd
...
...
@@ -2752,11 +2834,8 @@ class _AddorderScreenState extends State<AddorderScreen> {
],
),
),
if
(
provider
.
selectedBillingStateError
!=
null
)
errorWidget
(
context
,
provider
.
selectedBillingStateError
,
),
if
(
provider
.
selectedBillingStateError
!=
null
)
errorWidget
(
context
,
provider
.
selectedBillingStateError
),
TextWidget
(
context
,
"Billing District"
),
//dd
DropdownButtonHideUnderline
(
...
...
@@ -2871,7 +2950,7 @@ class _AddorderScreenState extends State<AddorderScreen> {
],
),
),
if
(
provider
.
selectedBillingDistrictError
!=
null
)
if
(
provider
.
selectedBillingDistrictError
!=
null
)
errorWidget
(
context
,
provider
.
selectedBillingDistrictError
,
...
...
@@ -2978,11 +3057,8 @@ class _AddorderScreenState extends State<AddorderScreen> {
],
),
),
if
(
provider
.
selectedBillingSubLocError
!=
null
)
errorWidget
(
context
,
provider
.
selectedBillingSubLocError
,
),
if
(
provider
.
selectedBillingSubLocError
!=
null
)
errorWidget
(
context
,
provider
.
selectedBillingSubLocError
),
textControllerWidget
(
context
,
provider
.
billingAddressController
,
...
...
@@ -2996,7 +3072,7 @@ class _AddorderScreenState extends State<AddorderScreen> {
focusNodes
[
2
],
TextInputAction
.
next
,
),
if
(
provider
.
billingAddressError
!=
null
)
if
(
provider
.
billingAddressError
!=
null
)
errorWidget
(
context
,
provider
.
billingAddressError
),
textControllerWidget
(
...
...
@@ -3013,7 +3089,7 @@ class _AddorderScreenState extends State<AddorderScreen> {
TextInputAction
.
done
,
6
,
),
if
(
provider
.
billingPincodeError
!=
null
)
if
(
provider
.
billingPincodeError
!=
null
)
errorWidget
(
context
,
provider
.
billingPincodeError
),
TextWidget
(
context
,
"Dispatch State"
),
...
...
@@ -3570,11 +3646,10 @@ class _AddorderScreenState extends State<AddorderScreen> {
),
scrollbarTheme:
ScrollbarThemeData
(
radius:
const
Radius
.
circular
(
15
),
thickness:
WidgetStateProperty
.
all
<
double
>(
6
,
),
thickness:
MaterialStateProperty
.
all
<
double
>(
6
),
thumbVisibility:
Widget
StateProperty
.
all
<
bool
>(
true
),
Material
StateProperty
.
all
<
bool
>(
true
),
),
),
menuItemStyleData:
const
MenuItemStyleData
(
...
...
@@ -3764,7 +3839,9 @@ class _AddorderScreenState extends State<AddorderScreen> {
provider
.
selectedTpcAgentValue
=
provider
.
tpcAgent
[
index
].
text
!;
print
(
"hfjkshfg
${provider.selectedTpcAgentID}
"
,
"hfjkshfg"
+
provider
.
selectedTpcAgentID
.
toString
(),
);
provider
.
dropDownTpcSearchController
...
...
@@ -3935,7 +4012,7 @@ class _AddorderScreenState extends State<AddorderScreen> {
Navigator
.
of
(
context
).
pop
(
false
);
provider
.
imgFromGallery
(
context
);
},
child:
SizedBox
(
child:
Container
(
height:
35
,
child:
Text
(
"Select photo from gallery"
),
),
...
...
@@ -3946,7 +4023,7 @@ class _AddorderScreenState extends State<AddorderScreen> {
Navigator
.
of
(
context
).
pop
(
false
);
provider
.
imgFromCamera
(
context
);
},
child:
SizedBox
(
child:
Container
(
height:
35
,
child:
Text
(
"Capture photo from camera"
),
),
...
...
@@ -3997,7 +4074,7 @@ class OrderForm extends StatelessWidget {
),
);
if
(
res
!=
null
)
{
print
(
"result
$res
"
);
print
(
"result
$
{
res
}
"
);
}
},
child:
Container
(
...
...
@@ -4061,7 +4138,7 @@ class OrderForm extends StatelessWidget {
),
);
if
(
res
!=
null
)
{
print
(
"result
$res
"
);
print
(
"result
$
{
res
}
"
);
}
},
child:
Container
(
...
...
lib/services/api_calling.dart
View file @
dc88a3f9
...
...
@@ -25,7 +25,9 @@ import 'package:generp/Models/crmModels/crmProspectDetailsAddLeadsResponse.dart'
import
'package:generp/Models/crmModels/crmProspectDetailsResponse.dart'
;
import
'package:generp/Models/financeModels/addDirectPaymentResponse.dart'
;
import
'package:generp/Models/financeModels/paymentRequisitionPaymentsListResponse.dart'
;
import
'package:generp/Models/hrmModels/advanceListResponse.dart'
;
import
'package:generp/Models/hrmModels/attendanceRequestListResponse.dart'
;
import
'package:generp/Models/hrmModels/casualLeaveHistoryResponse.dart'
;
import
'package:generp/Models/hrmModels/jobDescriptionResponse.dart'
;
import
'package:generp/Models/hrmModels/leaveApplicationDetailsResponse.dart'
;
import
'package:generp/Models/hrmModels/leaveApplicationLIstResponse.dart'
;
...
...
@@ -2371,16 +2373,38 @@ class ApiCalling {
empId
,
session
,
mode
,
leadId
,
feedback
,
followupType
,
inTime
,
loc
)
async
{
try
{
Map
<
String
,
String
>
data
=
{
'emp_id'
:
(
empId
).
toString
(),
'session_id'
:
(
session
).
toString
(),
'mode'
:
(
mode
).
toString
(),
'lead_id'
:
(
leadId
).
toString
(),
'feedback'
:
(
feedback
).
toString
(),
'followup_type'
:
(
followupType
).
toString
(),
'in_time'
:
(
inTime
).
toString
(),
'loc'
:
(
loc
).
toString
(),
};
debugPrint
(
"===========================Input to api "
);
debugPrint
(
"Lead Id:
${leadId}
"
);
debugPrint
(
"Follow Type:
${followupType}
"
);
debugPrint
(
"In Time:
${inTime}
"
);
debugPrint
(
"Location:
${loc}
"
);
debugPrint
(
"Mode:
${mode}
"
);
debugPrint
(
"feedback:
${feedback}
"
);
debugPrint
(
"=================End of INput================="
);
final
res
=
await
post
(
data
,
ordersAddOrderViewUrl
,
{});
if
(
res
!=
null
)
{
debugPrint
(
res
.
body
);
//
debugPrint(
"Response start ================== ${AddOrderViewResponse.fromJson(jsonDecode(res.body)).accountDetails?.name}"
);
return
AddOrderViewResponse
.
fromJson
(
jsonDecode
(
res
.
body
));
}
else
{
debugPrint
(
"Null Response"
);
...
...
@@ -3604,6 +3628,7 @@ class ApiCalling {
'lead_status'
:
leadStatus
.
toString
(),
'products'
:
products
.
toString
(),
};
debugPrint
(
"✅✅✅✅✅✅✅✅✅✅✅✅✅✅✅✅✅ Product deteails
${products}
"
);
final
res
=
await
post
(
data
,
crmNewProspectLeadSubmitUrl
,
{});
if
(
res
!=
null
)
{
print
(
data
);
...
...
@@ -3738,6 +3763,21 @@ class ApiCalling {
alphabet
,
pageNumber
,
)
async
{
debugPrint
(
'crmLeadListFilterSubmitAPI Input data:'
);
debugPrint
(
'empId:
$empId
'
);
debugPrint
(
'session:
$session
'
);
debugPrint
(
'mode:
$mode
'
);
debugPrint
(
'status:
$status
'
);
debugPrint
(
'openStatus:
$openStatus
'
);
debugPrint
(
'mob:
$mob
'
);
debugPrint
(
'com:
$com
'
);
debugPrint
(
'source:
$source
'
);
debugPrint
(
'reference:
$reference
'
);
debugPrint
(
'team:
$team
'
);
debugPrint
(
'segment:
$segment
'
);
debugPrint
(
'alphabet:
$alphabet
'
);
debugPrint
(
'pageNumber:
$pageNumber
'
);
debugPrint
(
'End of input data'
);
try
{
Map
<
String
,
String
>
data
=
{
'emp_id'
:
(
empId
).
toString
(),
...
...
@@ -3936,8 +3976,10 @@ class ApiCalling {
productId
,
qty
,
amount
,
remark
,
)
async
{
try
{
debugPrint
(
"💡💡💡💡💡💡💡💡💡AddEditProducts:
${remark}
"
);
Map
<
String
,
String
>
data
=
{
'emp_id'
:
(
empId
).
toString
(),
'session_id'
:
(
session
).
toString
(),
...
...
@@ -3947,7 +3989,9 @@ class ApiCalling {
'product_id'
:
(
productId
).
toString
(),
'qty'
:
(
qty
).
toString
(),
'amount'
:
(
amount
).
toString
(),
'remarks'
:
(
remark
).
toString
(),
};
final
res
=
await
post
(
data
,
crmLeadDetailsAddEditProductsUrl
,
{});
if
(
res
!=
null
)
{
print
(
"AddEditProducts
$data
"
);
...
...
@@ -4591,8 +4635,10 @@ class ApiCalling {
quantity
,
amount
,
leadStatus
,
remarks
,
)
async
{
try
{
debugPrint
(
"💡💡💡💡💡💡 remarks
$remarks
"
);
Map
<
String
,
String
>
data
=
{
'emp_id'
:
(
empId
).
toString
(),
'session_id'
:
(
session
).
toString
(),
...
...
@@ -4601,6 +4647,7 @@ class ApiCalling {
'quantity'
:
quantity
.
toString
(),
'amount'
:
amount
.
toString
(),
'lead_status'
:
leadStatus
.
toString
(),
'remarks'
:
remarks
.
toString
(),
};
final
res
=
await
post
(
data
,
crmProspectDetailsAddLeadUrl
,
{});
if
(
res
!=
null
)
{
...
...
@@ -5445,6 +5492,31 @@ class ApiCalling {
return
null
;
}
}
/// CasualLeaveHistory api
static
Future
<
CasualLeaveHistoryResponse
?>
casualLeaveHistoryAPI
(
session
,
empId
,
)
async
{
debugPrint
(
"🔥🔥🔥🔥🔥🔥🔥Response"
);
try
{
Map
<
String
,
String
>
data
=
{
'session_id'
:
(
session
).
toString
(),
'emp_id'
:
(
empId
).
toString
(),
};
final
res
=
await
post
(
data
,
CasuaLeaveHistoryUrl
,
{});
if
(
res
!=
null
)
{
print
(
data
);
debugPrint
(
res
.
body
);
return
CasualLeaveHistoryResponse
.
fromJson
(
jsonDecode
(
res
.
body
));
}
else
{
debugPrint
(
"Null Response"
);
return
null
;
}
}
catch
(
e
)
{
debugPrint
(
'hello bev=bug
$e
'
);
return
null
;
}
}
//add leave request
static
Future
<
CommonResponse
?>
leaveRequestAddAPI
(
...
...
@@ -5515,6 +5587,34 @@ class ApiCalling {
}
}
/// AdvanceListApi
static
Future
<
AdvanceListResponse
?>
advanceListAPI
(
session
,
empId
,
pageNumber
)
async
{
debugPrint
(
"🔥🔥🔥🔥🔥🔥🔥Response"
);
try
{
Map
<
String
,
String
>
data
=
{
'session_id'
:
(
session
).
toString
(),
'emp_id'
:
(
empId
).
toString
(),
'page_number'
:
(
pageNumber
).
toString
(),
// FIX: Use pageNumber parameter, not empId
};
final
res
=
await
post
(
data
,
AdvanceListUrl
,
{});
if
(
res
!=
null
)
{
print
(
"Request Data:
$data
"
);
debugPrint
(
"🔥🔥🔥🔥🔥🔥🔥 Response:
${res.body}
"
);
return
AdvanceListResponse
.
fromJson
(
jsonDecode
(
res
.
body
));
}
else
{
debugPrint
(
"Null Response"
);
return
null
;
}
}
catch
(
e
)
{
debugPrint
(
'API Error:
$e
'
);
return
null
;
}
}
// static Future<CommonResponse?> TpcIssueListApprovalAPI(
// empId,
// session,
...
...
lib/services/api_names.dart
View file @
dc88a3f9
...
...
@@ -181,9 +181,9 @@ const crmDashboardQuotationsUrl = "${baseUrl_test}crm_dashboard_quotations_list"
const
ogcharturl
=
"
${baseUrl_test}
organisation_structures"
;
const
JobDesciptionUrl
=
"
${baseUrl_test}
job_description"
;
///HRM
//Attendance
const
HrmAccessiblePagesUrl
=
"
${baseUrl_test}
hrm_accessible_pages"
;
const
AttendanceRequestListUrl
=
"
${baseUrl_test}
attendance_request_list"
;
const
AttendanceRequestDetailsUrl
=
"
${baseUrl_test}
attendance_request_details"
;
...
...
@@ -203,9 +203,9 @@ const LeaveApplicationDetailsUrl ="${baseUrl_test}leave_request_details";
const
LeaveRequestAdditionUrl
=
"
${baseUrl_test}
add_leave_request"
;
const
LeaveRequestRejectAprroveUrl
=
"
${baseUrl_test}
leaves_approve_reject"
;
const
CasuaLeaveHistoryUrl
=
"
${baseUrl_test}
casual_leave_history"
;
const
AdvanceListUrl
=
"
${baseUrl_test}
advance_list"
;
Prev
1
2
3
Next
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment