travel policy

This commit is contained in:
venbaittech 2025-05-26 18:21:30 +05:30
parent 8de950586a
commit b625692dad
7 changed files with 945 additions and 725 deletions

View File

@ -13,6 +13,7 @@ import 'package:flutter_quill/flutter_quill_internal.dart';
import 'package:flutter_quill/quill_delta.dart'; import 'package:flutter_quill/quill_delta.dart';
import 'package:flutter_quill_extensions/flutter_quill_extensions.dart'; import 'package:flutter_quill_extensions/flutter_quill_extensions.dart';
import 'package:frontend/Screens/myTemplates/quill_delta_sample.dart'; import 'package:frontend/Screens/myTemplates/quill_delta_sample.dart';
import 'package:go_router/go_router.dart';
import 'package:google_fonts/google_fonts.dart'; import 'package:google_fonts/google_fonts.dart';
import 'package:path/path.dart' as path; import 'package:path/path.dart' as path;
import 'package:responsive_builder/responsive_builder.dart'; import 'package:responsive_builder/responsive_builder.dart';
@ -24,6 +25,14 @@ import '../../utils/auth_utils.dart';
import '../../widgets/custom_user_travel.dart'; import '../../widgets/custom_user_travel.dart';
class Template extends StatefulWidget { class Template extends StatefulWidget {
final Map<String, dynamic>? templateData;
const Template({super.key, required this.templateData});
static Template fromState(GoRouterState state) {
return Template(templateData: state.extra as Map<String, dynamic>?);
}
@override @override
TemplateState createState() => TemplateState(); TemplateState createState() => TemplateState();
} }
@ -32,25 +41,53 @@ class TemplateState extends State<Template> {
final ApiService apiService = ApiService(); final ApiService apiService = ApiService();
final FocusNode _editorFocusNode = FocusNode(); final FocusNode _editorFocusNode = FocusNode();
final ScrollController _editorScrollController = ScrollController(); // final ScrollController _editorScrollController = ScrollController();
final QuillController _controller = QuillController.basic(); // final QuillController _controller = QuillController.basic();
Color layoutColor = Colors.redAccent; Color layoutColor = Colors.redAccent;
Color bodyColor = Colors.white; Color bodyColor = Colors.white;
final Map<String, TextEditingController> controllers = {};
List<String> dataHeader = ["subject"];
Map<String, dynamic> get TemplateData {
final data = {
// "org_id": orgId;
"template_name": controllers["templateName"]?.text,
"subject": controllers["subject"]?.text,
"body_html": controllers["bodyData"]?.text,
"placeholder": [],
// "created_by": userId
};
// Only add group_id if it's an edit operation
// if (widget.templateData != null && widget.templateData!.containsKey('group_id')) {
// data["template_id"] = templateData;
// }
return data;
}
@override @override
void initState() { void initState() {
super.initState(); super.initState();
for (var field in dataHeader) {
controllers[field] = TextEditingController();
}
WidgetsBinding.instance.addPostFrameCallback((_) { WidgetsBinding.instance.addPostFrameCallback((_) {
_editorFocusNode.requestFocus(); // Ensure focus is requested _editorFocusNode.requestFocus(); // Ensure focus is requested
}); });
// _controller.document = Document.fromJson(kQuillDefaultSample); // _controller.document = Document.fromJson(kQuillDefaultSample);
// _controller.readOnly = false;
updateData();
loadInitialData(); loadInitialData();
} }
@override @override
void dispose() { void dispose() {
_controller.dispose(); // controllers.dispose();
_editorScrollController.dispose(); // _editorScrollController.dispose();
_editorFocusNode.dispose(); _editorFocusNode.dispose();
super.dispose(); super.dispose();
} }
@ -70,6 +107,27 @@ class TemplateState extends State<Template> {
}); });
} }
Future<void> updateData() async {
// Ensure apiselectedUser is not null before printing
if (widget.templateData != null) {
print("API Selected User Has Data - ${widget.templateData}");
print(
"API Selected User Has - ${widget.templateData?["templateData"]?["subject"]}");
setState(() {
// Wrap in setState to update the UI
controllers["subject"]?.text =
widget.templateData?["templateData"]?["subject"] ?? "";
// if (widget.group?["international_policy_id"] != null) {
// selectedInternational =
// widget.group!["international_policy_id"].toString();
// }
});
} else {
print("API Selected User Has Data - No data available yet");
}
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return ResponsiveBuilder(builder: (context, sizingInfo) { return ResponsiveBuilder(builder: (context, sizingInfo) {
@ -146,7 +204,7 @@ class TemplateState extends State<Template> {
height: 40, height: 40,
child: TextField( child: TextField(
style: GoogleFonts.poppins(fontSize: 12, color: Colors.black), style: GoogleFonts.poppins(fontSize: 12, color: Colors.black),
// controller: _controller[""], controller: controllers["subject"],
onChanged: (value) { onChanged: (value) {
// _clearError("local_id_num"); // _clearError("local_id_num");
}, },
@ -181,99 +239,99 @@ class TemplateState extends State<Template> {
const SizedBox(height: 10), const SizedBox(height: 10),
// Modern toolbar // Modern toolbar
QuillSimpleToolbar( // QuillSimpleToolbar(
controller: _controller, // controller: _controller,
config: QuillSimpleToolbarConfig( // config: QuillSimpleToolbarConfig(
embedButtons: FlutterQuillEmbeds.toolbarButtons(), // embedButtons: FlutterQuillEmbeds.toolbarButtons(),
showClipboardPaste: true, // showClipboardPaste: true,
customButtons: [ // customButtons: [
QuillToolbarCustomButtonOptions( // QuillToolbarCustomButtonOptions(
icon: const Icon(Icons.add_alarm_rounded), // icon: const Icon(Icons.add_alarm_rounded),
onPressed: () { // onPressed: () {
_controller.document.insert( // _controller.document.insert(
_controller.selection.extentOffset, // _controller.selection.extentOffset,
TimeStampEmbed( // TimeStampEmbed(
DateTime.now().toString(), // DateTime.now().toString(),
), // ),
); // );
//
_controller.updateSelection( // _controller.updateSelection(
TextSelection.collapsed( // TextSelection.collapsed(
offset: _controller.selection.extentOffset + 1, // offset: _controller.selection.extentOffset + 1,
), // ),
ChangeSource.local, // ChangeSource.local,
); // );
}, // },
), // ),
], // ],
buttonOptions: QuillSimpleToolbarButtonOptions( // buttonOptions: QuillSimpleToolbarButtonOptions(
base: QuillToolbarBaseButtonOptions( // base: QuillToolbarBaseButtonOptions(
afterButtonPressed: () { // afterButtonPressed: () {
final isDesktop = { // final isDesktop = {
TargetPlatform.linux, // TargetPlatform.linux,
TargetPlatform.windows, // TargetPlatform.windows,
TargetPlatform.macOS // TargetPlatform.macOS
}.contains(defaultTargetPlatform); // }.contains(defaultTargetPlatform);
if (isDesktop) { // if (isDesktop) {
_editorFocusNode.requestFocus(); // _editorFocusNode.requestFocus();
} // }
}, // },
), // ),
linkStyle: QuillToolbarLinkStyleButtonOptions( // linkStyle: QuillToolbarLinkStyleButtonOptions(
validateLink: (link) { // validateLink: (link) {
// Treats all links as valid. When launching the URL, // // Treats all links as valid. When launching the URL,
// `https://` is prefixed if the link is incomplete (e.g., `google.com` `https://google.com`) // // `https://` is prefixed if the link is incomplete (e.g., `google.com` `https://google.com`)
// however this happens only within the editor. // // however this happens only within the editor.
return true; // return true;
}, // },
), // ),
), // ),
), // ),
), // ),
const SizedBox(height: 10), // const SizedBox(height: 10),
//
// Modern editor // // Modern editor
Container( // Container(
height: 300, // height: 300,
decoration: BoxDecoration( // decoration: BoxDecoration(
border: Border.all(color: Colors.grey), // border: Border.all(color: Colors.grey),
borderRadius: BorderRadius.circular(8), // borderRadius: BorderRadius.circular(8),
), // ),
child: QuillEditor.basic( // child: QuillEditor.basic(
focusNode: _editorFocusNode, // focusNode: _editorFocusNode,
scrollController: _editorScrollController, // scrollController: _editorScrollController,
controller: _controller, // controller: _controller,
// readOnly: true, // // readOnly: true,
config: QuillEditorConfig( // config: QuillEditorConfig(
requestKeyboardFocusOnCheckListChanged: false, // requestKeyboardFocusOnCheckListChanged: false,
// readOnlyMouseCursor: SystemMouseCursors.text, // // readOnlyMouseCursor: SystemMouseCursors.text,
enableScribble: true, // enableScribble: true,
//
padding: const EdgeInsets.all(8), // padding: const EdgeInsets.all(8),
placeholder: 'Type something...', // placeholder: 'Type something...',
embedBuilders: [ // embedBuilders: [
...FlutterQuillEmbeds.editorBuilders( // ...FlutterQuillEmbeds.editorBuilders(
imageEmbedConfig: QuillEditorImageEmbedConfig( // imageEmbedConfig: QuillEditorImageEmbedConfig(
imageProviderBuilder: (context, imageUrl) { // imageProviderBuilder: (context, imageUrl) {
// https://pub.dev/packages/flutter_quill_extensions#-image-assets // // https://pub.dev/packages/flutter_quill_extensions#-image-assets
if (imageUrl.startsWith('assets/')) { // if (imageUrl.startsWith('assets/')) {
return AssetImage(imageUrl); // return AssetImage(imageUrl);
} // }
return null; // return null;
}, // },
), // ),
videoEmbedConfig: QuillEditorVideoEmbedConfig( // videoEmbedConfig: QuillEditorVideoEmbedConfig(
customVideoBuilder: (videoUrl, readOnly) { // customVideoBuilder: (videoUrl, readOnly) {
// To load YouTube videos https://github.com/singerdmx/flutter-quill/releases/tag/v10.8.0 // // To load YouTube videos https://github.com/singerdmx/flutter-quill/releases/tag/v10.8.0
return null; // return null;
}, // },
), // ),
), // ),
TimeStampEmbedBuilder(), // TimeStampEmbedBuilder(),
], // ],
), // ),
), // ),
), // ),
], ],
); );
} }

View File

@ -425,42 +425,42 @@ class TemplatesListState extends State<TemplatesList> {
), ),
), ),
// SizedBox(width: 16), // SizedBox(width: 16),
Spacer(), // Spacer(),
//
ElevatedButton( // ElevatedButton(
style: ElevatedButton.styleFrom( // style: ElevatedButton.styleFrom(
backgroundColor: Color(0xFF114D8B), // backgroundColor: Color(0xFF114D8B),
foregroundColor: Colors.white, // foregroundColor: Colors.white,
disabledBackgroundColor: Color(0xFF114D8B), // disabledBackgroundColor: Color(0xFF114D8B),
disabledForegroundColor: Colors.white, // disabledForegroundColor: Colors.white,
shape: RoundedRectangleBorder( // shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8), // borderRadius: BorderRadius.circular(8),
side: // side:
BorderSide(color: Color(0xFF114D8B), width: 2), // BorderSide(color: Color(0xFF114D8B), width: 2),
), // ),
padding: EdgeInsets.symmetric( // padding: EdgeInsets.symmetric(
horizontal: 20, vertical: 12), // horizontal: 20, vertical: 12),
), // ),
onPressed: () async {}, // onPressed: () async {},
child: Row( // child: Row(
mainAxisSize: // mainAxisSize:
MainAxisSize.min, // Ensures content fits nicely // MainAxisSize.min, // Ensures content fits nicely
children: [ // children: [
Text( // Text(
"Add Templates", // "Add Templates",
style: GoogleFonts.poppins( // style: GoogleFonts.poppins(
fontSize: isDesktop ? 13 : 11, // fontSize: isDesktop ? 13 : 11,
), // ),
), // ),
SizedBox(width: 8), // spacing between icon and text // SizedBox(width: 8), // spacing between icon and text
Icon( // Icon(
Icons.add_circle_outline_rounded, // Icons.add_circle_outline_rounded,
size: 15, // size: 15,
color: Colors.white, // color: Colors.white,
), // ),
], // ],
), // ),
), // ),
], ],
), ),
@ -661,15 +661,20 @@ class TemplatesListState extends State<TemplatesList> {
// final userId = getUserId(user['user_id']); // final userId = getUserId(user['user_id']);
// final usersData = await getUserDetails(userId); // final usersData = await getUserDetails(userId);
// //
// context.go('/template');
final templateId = int.tryParse( final templateId = int.tryParse(
forex['forex_perdiem_id'] forex['template_id'].toString());
.toString());
if (templateId != null) { if (templateId != null) {
print("templateId -- $templateId"); print("templateId -- $templateId");
final data = await apiService final data = await apiService
.getTemplateFind(templateId); .getTemplateFind(templateId);
print("ForexId -- $data"); print("ForexId -- $data");
context.go('/template', extra: {
'templateData': data,
});
} else { } else {
print("Invalid Forex ID"); print("Invalid Forex ID");
} }

View File

@ -581,27 +581,64 @@ class _PolicyState extends State<Policy> {
), ),
], ],
isDesktop isDesktop
? Expanded( ? Container(
// color: Colors.yellow.shade50,
height: MediaQuery.of(context).size.height * 0.54,
child: SingleChildScrollView(
scrollDirection: Axis.vertical,
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
_buildPolicyCategoryList(isDesktop), Column(
children: [
_buildPolicyOrdering(isDesktop),
_buildPolicyCategory(isDesktop), _buildPolicyCategory(isDesktop),
], ],
), ),
Column(
children: [
_buildPolicyCategoryList(isDesktop),
],
),
],
),
),
) )
: Expanded( : Expanded(
child: Column( child: Row(
children: [ children: [
_buildPolicyCategoryList(isDesktop), // _buildPolicyOrdering(isDesktop),
_buildPolicyCategory(isDesktop), _buildPolicyCategory(isDesktop),
], ],
), ),
), ),
// isDesktop
// ? Expanded(
// child: Row(
// children: [
// _buildPolicyCategory(isDesktop),
// _buildPolicyCategoryList(isDesktop),
// ],
// ),
// )
// : Expanded(
// child: Column(
// children: [
// _buildPolicyCategoryList(isDesktop),
// _buildPolicyCategory(isDesktop),
// ],
// ),
// ),
], ],
), ),
); );
} }
// Widget _buildServiceSelect(bool isDesktop){
// return [];
// }
Widget _buildPolicyNameField(bool isDesktop) { Widget _buildPolicyNameField(bool isDesktop) {
return Column( return Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
@ -665,7 +702,8 @@ class _PolicyState extends State<Policy> {
Widget _buildPolicyCategoryList(bool isDesktop) { Widget _buildPolicyCategoryList(bool isDesktop) {
return Container( return Container(
color: Colors.white, // color: Colors.white,
height: MediaQuery.of(context).size.height,
// color: Colors.blueGrey.shade200, // color: Colors.blueGrey.shade200,
width: isDesktop ? MediaQuery.of(context).size.width * 0.15 : null, width: isDesktop ? MediaQuery.of(context).size.width * 0.15 : null,
child: isDesktop child: isDesktop
@ -685,6 +723,129 @@ class _PolicyState extends State<Policy> {
); );
} }
Widget _buildPolicyOrdering(bool isDesktop) {
return Container(
// height: 50,
// color: Colors.white,
// color: Colors.blueGrey.shade200,
padding: isDesktop ? const EdgeInsets.only(left: 35) : null,
width: isDesktop ? MediaQuery.of(context).size.width * 0.62 : null,
// width: isDesktop ? MediaQuery.of(context).size.width * 0.75 : null,
child: isDesktop
? Container(
// color: Colors.amber,
child: Expanded(
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [_buildPolicyServiceOrdering(isDesktop)],
),
),
)
: Container(
// color: Colors.amber,
child: Expanded(
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [_buildPolicyServiceOrdering(isDesktop)],
),
),
),
);
}
Widget _buildPolicyServiceOrdering(bool isDesktop) {
if (ServicesChoosed == null) {
return const Center(child: CircularProgressIndicator());
}
// Sort services by 'order'
ServicesChoosed!
.sort((a, b) => (a['order'] ?? 0).compareTo(b['order'] ?? 0));
List<String> services =
ServicesChoosed!.map((service) => service['name'].toString()).toList();
return Expanded(
child: SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Flex(
direction: Axis.horizontal,
children: services.asMap().entries.map((entry) {
int index = entry.key + 1;
String service = entry.value;
bool isSelected = selectedServiceIndex.value == index.toString();
return SizedBox(
// width: isDesktop ? 140 : null,
height: isDesktop
? max((MediaQuery.of(context).size.height * 0.075), 10)
: 45,
// max((MediaQuery.of(context).size.height * 0.09), 10)
child: GestureDetector(
onTap: () {
print("Selected Services - $service - $index");
setState(() {
selectedServiceIndex.value = index.toString();
selectedService = service;
if (selectedService == "Flight" ||
selectedService == "Train") {
showClass = true;
showCost = true;
int serviceCode = selectedService == "Flight" ? 1 : 2;
policyCriteriaKey.currentState?.fetchTrainFlightClass();
} else if (selectedService == "Accommodation") {
showClass = true;
showCost = false;
} else {
showClass = false;
showCost = false;
}
});
},
child: Container(
margin: const EdgeInsets.all(5),
padding: isDesktop
? const EdgeInsets.all(8)
: const EdgeInsets.symmetric(
horizontal: 8, vertical: 3),
alignment: Alignment.center,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text(
service,
style: TextStyle(
color: isSelected
? const Color(0xFF114D8B)
: Colors.black87,
fontSize: 13,
fontWeight:
isSelected ? FontWeight.bold : FontWeight.w100,
decoration: TextDecoration
.none, // remove built-in underline
),
),
if (isSelected)
const SizedBox(
height: 1), // spacing between text and underline
if (isSelected)
Container(
height: 2,
width: 30, // or based on text width
color: const Color(0xFF114D8B),
),
],
),
),
));
}).toList(),
),
),
);
}
Widget _buildPolicySubCategoryList(bool isDesktop) { Widget _buildPolicySubCategoryList(bool isDesktop) {
// List<String> services = [ // List<String> services = [
// "Flight", // "Flight",
@ -727,21 +888,21 @@ class _PolicyState extends State<Policy> {
print("Selected Services - $service - $index"); print("Selected Services - $service - $index");
setState(() { setState(() {
selectedServiceIndex.value = index.toString(); selectedServiceIndex.value = index.toString();
selectedService = service; // selectedService = service;
//
if (selectedService == "Flight" || // if (selectedService == "Flight" ||
selectedService == "Train") { // selectedService == "Train") {
showClass = true; // showClass = true;
showCost = true; // showCost = true;
int serviceCode = selectedService == "Flight" ? 1 : 2; // int serviceCode = selectedService == "Flight" ? 1 : 2;
policyCriteriaKey.currentState?.fetchTrainFlightClass(); // policyCriteriaKey.currentState?.fetchTrainFlightClass();
} else if (selectedService == "Accommodation") { // } else if (selectedService == "Accommodation") {
showClass = true; // showClass = true;
showCost = false; // showCost = false;
} else { // } else {
showClass = false; // showClass = false;
showCost = false; // showCost = false;
} // }
}); });
}, },
child: Container( child: Container(
@ -785,10 +946,10 @@ class _PolicyState extends State<Policy> {
} }
Widget _buildPolicyCategory(bool isDesktop) { Widget _buildPolicyCategory(bool isDesktop) {
return Expanded( return Container(
child: Container(
margin: EdgeInsets.all(10), margin: EdgeInsets.all(10),
// color: Colors.brown.shade100, // color: Colors.brown.shade100,
// child: Text("data"),
// color: Colors.white60, // color: Colors.white60,
child: PolicyCriteria( child: PolicyCriteria(
key: policyCriteriaKey, key: policyCriteriaKey,
@ -808,8 +969,7 @@ class _PolicyState extends State<Policy> {
}); });
}); });
}, },
)), ));
);
} }
List<Widget> _buildTripType(bool isDesktop) { List<Widget> _buildTripType(bool isDesktop) {

View File

@ -322,35 +322,36 @@ class PolicyCriteriaState extends State<PolicyCriteria> {
Row( Row(
mainAxisAlignment: MainAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start,
children: [ children: [
Text( Padding(
padding: const EdgeInsets.only(left: 28.0),
child: Text(
" Policy Criteria For ${widget.selectedService} ", " Policy Criteria For ${widget.selectedService} ",
style: TextStyle( style: TextStyle(
fontSize: 13, fontSize: 13,
color: Color(0xFF9E9DBD), color: Color(0xFF9E9DBD),
fontWeight: FontWeight.bold), fontWeight: FontWeight.bold),
),
) )
], ],
), ),
if (widget.isClass!) if (widget.isClass!)
widget.isDesktop ? SizedBox(height: 5) : SizedBox(height: 5), widget.isDesktop ? SizedBox(height: 5) : SizedBox(height: 5),
Padding( Padding(
padding: const EdgeInsets.only(right: 18.0), padding: const EdgeInsets.only(left: 28.0),
child: Row( child: Row(
children: [ children: [
Expanded( Container(
child: Container(
// color: Colors.grey, // color: Colors.grey,
padding: const EdgeInsets.only( padding:
top: 5, bottom: 5, left: 5, right: 5), const EdgeInsets.only(top: 5, bottom: 5, left: 5, right: 5),
child: widget.isDesktop child: widget.isDesktop
? Row( ? Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
if (widget.isClass) if (widget.isClass)
buildClassWidget(widget.isDesktop), buildClassWidget(widget.isDesktop),
SizedBox(height: 10), SizedBox(width: 30),
if (widget.isCost!) if (widget.isCost!) buildCostWidget(widget.isDesktop),
buildCostWidget(widget.isDesktop),
], ],
) )
: Column( : Column(
@ -359,12 +360,10 @@ class PolicyCriteriaState extends State<PolicyCriteria> {
if (widget.isClass!) if (widget.isClass!)
buildClassWidget(widget.isDesktop), buildClassWidget(widget.isDesktop),
SizedBox(height: 10), SizedBox(height: 10),
if (widget.isCost!) if (widget.isCost!) buildCostWidget(widget.isDesktop),
buildCostWidget(widget.isDesktop),
], ],
), ),
), ),
),
], ],
), ),
), ),
@ -380,8 +379,7 @@ class PolicyCriteriaState extends State<PolicyCriteria> {
], ],
), ),
if (validationErrors[ServiceId] != null) SizedBox(height: 15), if (validationErrors[ServiceId] != null) SizedBox(height: 15),
Expanded( Container(
child: Container(
decoration: BoxDecoration( decoration: BoxDecoration(
border: null, border: null,
// border: Border.all( // border: Border.all(
@ -390,17 +388,14 @@ class PolicyCriteriaState extends State<PolicyCriteria> {
borderRadius: BorderRadius.circular(8), borderRadius: BorderRadius.circular(8),
// color: Colors.brown.shade200, // color: Colors.brown.shade200,
), ),
child: SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Container( child: Container(
child: Column( child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly, mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [ children: [
Expanded( Container(
child: Container(
// color: Colors.grey.shade100, // color: Colors.grey.shade100,
width: widget.isDesktop width: widget.isDesktop
? MediaQuery.of(context).size.width * 0.63 ? MediaQuery.of(context).size.width * 0.56
: 600, : 600,
child: Column( child: Column(
children: [ children: [
@ -456,18 +451,17 @@ class PolicyCriteriaState extends State<PolicyCriteria> {
SizedBox( SizedBox(
height: 180, height: 180,
child: SingleChildScrollView( child: SingleChildScrollView(
scrollDirection: Axis.vertical, // scrollDirection: Axis.vertical,
child: Container( child: Container(
// color: Colors.grey, // color: Colors.grey,
margin: const EdgeInsets.only( margin:
right: 20, left: 20), const EdgeInsets.only(right: 20, left: 20),
// color: Colors.grey.shade100, // color: Colors.grey.shade100,
child: Column(children: [ child: Column(children: [
Container( Container(
padding: const EdgeInsets.all(10), padding: const EdgeInsets.all(10),
child: Row( child: Row(
mainAxisAlignment: mainAxisAlignment: MainAxisAlignment.end,
MainAxisAlignment.end,
children: [ children: [
Text("Approver 1"), Text("Approver 1"),
Spacer(), Spacer(),
@ -478,8 +472,7 @@ class PolicyCriteriaState extends State<PolicyCriteria> {
height: 40, height: 40,
child: DropdownSearch<String>( child: DropdownSearch<String>(
selectedItem: selectedItem:
FirstApproverAction[ FirstApproverAction[ServiceId],
ServiceId],
// enabled: !isViewMode, // enabled: !isViewMode,
popupProps: PopupProps.menu( popupProps: PopupProps.menu(
// showSearchBox: true, // showSearchBox: true,
@ -487,11 +480,11 @@ class PolicyCriteriaState extends State<PolicyCriteria> {
.loose, // Allows flexible height .loose, // Allows flexible height
constraints: BoxConstraints( constraints: BoxConstraints(
maxHeight: 250), maxHeight: 250),
itemBuilder: (context, item, itemBuilder:
isSelected) => (context, item, isSelected) =>
Padding( Padding(
padding: const EdgeInsets padding:
.symmetric( const EdgeInsets.symmetric(
horizontal: 16.0, horizontal: 16.0,
vertical: 8.0), vertical: 8.0),
child: Text( child: Text(
@ -525,23 +518,19 @@ class PolicyCriteriaState extends State<PolicyCriteria> {
(context, selectedItem) => (context, selectedItem) =>
Align( Align(
// Center-align selected item // Center-align selected item
alignment: alignment: Alignment.centerLeft,
Alignment.centerLeft,
child: Text( child: Text(
selectedItem ?? "Select", selectedItem ?? "Select",
style: TextStyle( style: TextStyle(
fontSize: 12, fontSize: 12,
color: Color( color: Color(0xFF114D8B)),
0xFF114D8B)),
), ),
), ),
onChanged: onChanged: (String? newValue) {
(String? newValue) {
setState(() { setState(() {
// Find the country_code based on selected country_name // Find the country_code based on selected country_name
FirstApproverAction[ FirstApproverAction[
ServiceId!] = ServiceId!] = newValue;
newValue;
// print("selectedUserType - $selectedUserType"); // print("selectedUserType - $selectedUserType");
@ -570,7 +559,8 @@ class PolicyCriteriaState extends State<PolicyCriteria> {
decoration: BoxDecoration( decoration: BoxDecoration(
shape: BoxShape.circle, shape: BoxShape.circle,
border: Border.all( border: Border.all(
color: (SelectedParallelProcess[ color:
(SelectedParallelProcess[
ServiceId] == ServiceId] ==
"1") "1")
? Colors.green ? Colors.green
@ -580,8 +570,7 @@ class PolicyCriteriaState extends State<PolicyCriteria> {
child: Icon( child: Icon(
Icons.check_circle, Icons.check_circle,
size: 20, size: 20,
color: color: (SelectedParallelProcess[
(SelectedParallelProcess[
ServiceId] == ServiceId] ==
"1") "1")
? Colors.green ? Colors.green
@ -595,8 +584,7 @@ class PolicyCriteriaState extends State<PolicyCriteria> {
Container( Container(
padding: const EdgeInsets.all(10), padding: const EdgeInsets.all(10),
child: Row( child: Row(
mainAxisAlignment: mainAxisAlignment: MainAxisAlignment.end,
MainAxisAlignment.end,
children: [ children: [
Text("Approver 2"), Text("Approver 2"),
Spacer(), Spacer(),
@ -607,8 +595,7 @@ class PolicyCriteriaState extends State<PolicyCriteria> {
height: 40, height: 40,
child: DropdownSearch<String>( child: DropdownSearch<String>(
selectedItem: selectedItem:
SecondApproverAction[ SecondApproverAction[ServiceId],
ServiceId],
// enabled: !isViewMode, // enabled: !isViewMode,
popupProps: PopupProps.menu( popupProps: PopupProps.menu(
// showSearchBox: true, // showSearchBox: true,
@ -616,11 +603,11 @@ class PolicyCriteriaState extends State<PolicyCriteria> {
.loose, // Allows flexible height .loose, // Allows flexible height
constraints: BoxConstraints( constraints: BoxConstraints(
maxHeight: 250), maxHeight: 250),
itemBuilder: (context, item, itemBuilder:
isSelected) => (context, item, isSelected) =>
Padding( Padding(
padding: const EdgeInsets padding:
.symmetric( const EdgeInsets.symmetric(
horizontal: 16.0, horizontal: 16.0,
vertical: 8.0), vertical: 8.0),
child: Text( child: Text(
@ -654,23 +641,19 @@ class PolicyCriteriaState extends State<PolicyCriteria> {
(context, selectedItem) => (context, selectedItem) =>
Align( Align(
// Center-align selected item // Center-align selected item
alignment: alignment: Alignment.centerLeft,
Alignment.centerLeft,
child: Text( child: Text(
selectedItem ?? "Select", selectedItem ?? "Select",
style: TextStyle( style: TextStyle(
fontSize: 12, fontSize: 12,
color: Color( color: Color(0xFF114D8B)),
0xFF114D8B)),
), ),
), ),
onChanged: onChanged: (String? newValue) {
(String? newValue) {
setState(() { setState(() {
// Find the country_code based on selected country_name // Find the country_code based on selected country_name
SecondApproverAction[ SecondApproverAction[
ServiceId!] = ServiceId!] = newValue;
newValue;
// print("selectedUserType - $selectedUserType"); // print("selectedUserType - $selectedUserType");
@ -729,8 +712,7 @@ class PolicyCriteriaState extends State<PolicyCriteria> {
Container( Container(
padding: const EdgeInsets.all(10), padding: const EdgeInsets.all(10),
child: Row( child: Row(
mainAxisAlignment: mainAxisAlignment: MainAxisAlignment.end,
MainAxisAlignment.end,
children: [ children: [
Text("Approver 3"), Text("Approver 3"),
Spacer(), Spacer(),
@ -741,8 +723,7 @@ class PolicyCriteriaState extends State<PolicyCriteria> {
height: 40, height: 40,
child: DropdownSearch<String>( child: DropdownSearch<String>(
selectedItem: selectedItem:
ThirdApproverAction[ ThirdApproverAction[ServiceId],
ServiceId],
// enabled: !isViewMode, // enabled: !isViewMode,
popupProps: PopupProps.menu( popupProps: PopupProps.menu(
// showSearchBox: true, // showSearchBox: true,
@ -750,11 +731,11 @@ class PolicyCriteriaState extends State<PolicyCriteria> {
.loose, // Allows flexible height .loose, // Allows flexible height
constraints: BoxConstraints( constraints: BoxConstraints(
maxHeight: 250), maxHeight: 250),
itemBuilder: (context, item, itemBuilder:
isSelected) => (context, item, isSelected) =>
Padding( Padding(
padding: const EdgeInsets padding:
.symmetric( const EdgeInsets.symmetric(
horizontal: 16.0, horizontal: 16.0,
vertical: 8.0), vertical: 8.0),
child: Text( child: Text(
@ -788,23 +769,19 @@ class PolicyCriteriaState extends State<PolicyCriteria> {
(context, selectedItem) => (context, selectedItem) =>
Align( Align(
// Center-align selected item // Center-align selected item
alignment: alignment: Alignment.centerLeft,
Alignment.centerLeft,
child: Text( child: Text(
selectedItem ?? "Select", selectedItem ?? "Select",
style: TextStyle( style: TextStyle(
fontSize: 12, fontSize: 12,
color: Color( color: Color(0xFF114D8B)),
0xFF114D8B)),
), ),
), ),
onChanged: onChanged: (String? newValue) {
(String? newValue) {
setState(() { setState(() {
// Find the country_code based on selected country_name // Find the country_code based on selected country_name
ThirdApproverAction[ ThirdApproverAction[
ServiceId!] = ServiceId!] = newValue;
newValue;
// print("selectedUserType - $selectedUserType"); // print("selectedUserType - $selectedUserType");
@ -846,7 +823,10 @@ class PolicyCriteriaState extends State<PolicyCriteria> {
child: Icon( child: Icon(
Icons.check_circle, Icons.check_circle,
size: 20, size: 20,
color: ((SelectedParallelProcess[ServiceId] == "1") || color:
((SelectedParallelProcess[
ServiceId] ==
"1") ||
(SelectedParallelProcess[ (SelectedParallelProcess[
ServiceId] == ServiceId] ==
"2") || "2") ||
@ -867,13 +847,10 @@ class PolicyCriteriaState extends State<PolicyCriteria> {
) )
], ],
)), )),
),
], ],
), ),
), ),
), ),
),
),
], ],
); );
} }

View File

@ -6,7 +6,7 @@ import 'package:shared_preferences/shared_preferences.dart'; // don't forget
import '../services/apiService.dart'; import '../services/apiService.dart';
import '../utils/auth_utils.dart'; import '../utils/auth_utils.dart';
enum TabSelection { allTrips, myTrips, myApprovals, allMenu } enum TabSelection { allTrips, myTrips, myApprovals, allMenu, dashboard }
class CustomAppBar extends StatefulWidget implements PreferredSizeWidget { class CustomAppBar extends StatefulWidget implements PreferredSizeWidget {
final bool isDesktop; final bool isDesktop;
@ -56,7 +56,8 @@ class _CustomAppBarState extends State<CustomAppBar> {
}); });
if (userData?["role"] == "Org Admin" || if (userData?["role"] == "Org Admin" ||
userData?["role"] == "Travel Admin") { userData?["role"] == "Travel Admin") {
selectedTab = TabSelection.allTrips; selectedTab = TabSelection.dashboard;
// selectedTab = TabSelection.allTrips;
} else { } else {
selectedTab = TabSelection.myTrips; selectedTab = TabSelection.myTrips;
} }
@ -196,6 +197,8 @@ class _CustomAppBarState extends State<CustomAppBar> {
selectedTab = TabSelection.myTrips; selectedTab = TabSelection.myTrips;
} else if (location.contains('/ApprovalList')) { } else if (location.contains('/ApprovalList')) {
selectedTab = TabSelection.myApprovals; selectedTab = TabSelection.myApprovals;
} else if (location.contains('/StatusDashboard')) {
selectedTab = TabSelection.dashboard;
} else { } else {
selectedTab = TabSelection.allMenu; selectedTab = TabSelection.allMenu;
} }
@ -262,6 +265,20 @@ class _CustomAppBarState extends State<CustomAppBar> {
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
if (userData?["role"] == "Org Admin" ||
userData?["role"] == "Travel Admin")
buildNavItem(
"Dashboard",
() => handleTabChange(
TabSelection.dashboard, '/StatusDashboard'),
layoutColor!,
isSelected: selectedTab == TabSelection.dashboard,
icon: Icons.dashboard,
// icon: Icons.insights_outlined,
),
if (userData?["role"] == "Org Admin" ||
userData?["role"] == "Travel Admin")
const SizedBox(width: 20),
if (userData?["role"] == "Org Admin" || if (userData?["role"] == "Org Admin" ||
userData?["role"] == "Travel Admin") userData?["role"] == "Travel Admin")
buildNavItem( buildNavItem(
@ -352,8 +369,7 @@ class _CustomAppBarState extends State<CustomAppBar> {
// context.go('/templateList'); // context.go('/templateList');
// case '/template': // case '/template':
// context.go('/template'); // context.go('/template');
case '/StatusDashboard':
context.go('/StatusDashboard');
case '/CreateUserDetails': case '/CreateUserDetails':
context.go( context.go(
"/CreateUserDetails", "/CreateUserDetails",
@ -481,11 +497,7 @@ final List<Map<String, dynamic>> menuItems = [
'icon': Icons.manage_accounts, 'icon': Icons.manage_accounts,
'label': 'User Management' 'label': 'User Management'
}, },
{
'value': '/StatusDashboard',
'icon': Icons.dashboard_sharp,
'label': 'Status Dashboard'
},
// {'value': '/group', 'icon': Icons.group, 'label': 'Group'}, // {'value': '/group', 'icon': Icons.group, 'label': 'Group'},
// {'value': '/department', 'icon': Icons.group, 'label': 'Department'}, // {'value': '/department', 'icon': Icons.group, 'label': 'Department'},
// {'value': '/PolicyList', 'icon': Icons.policy, 'label': 'Policy'}, // {'value': '/PolicyList', 'icon': Icons.policy, 'label': 'Policy'},

View File

@ -123,7 +123,10 @@ final GoRouter router = GoRouter(
), ),
GoRoute( GoRoute(
path: '/template', path: '/template',
builder: (context, state) => Template(), // builder: (context, state) => Template(),
pageBuilder: (context, state) => MaterialPage(
child: Template.fromState(state),
),
), ),
GoRoute( GoRoute(
path: '/approvallist', path: '/approvallist',

View File

@ -896,7 +896,7 @@ class ApiService {
throw Exception('Token not found. Please log in.'); throw Exception('Token not found. Please log in.');
} }
final response = await http.get( final response = await http.put(
Uri.parse(apiUrldata), Uri.parse(apiUrldata),
headers: { headers: {
'Authorization': 'Bearer $token', 'Authorization': 'Bearer $token',
@ -911,19 +911,26 @@ class ApiService {
// print(data.runtimeType); // print(data.runtimeType);
// print(data); // print(data);
if (!data.containsKey('data') || data['data'] is! List) { // if (!data.containsKey('data') || data['data'] is! List) {
// throw Exception(
// "Invalid response format: 'data' field is missing or not a List");
// }
//
// final List<Map<String, dynamic>> listData =
// List<Map<String, dynamic>>.from(data['data']);
//
// if (listData.isEmpty) {
// throw Exception("No department found with ID $id");
// }
//
// return listData[0];
if (!data.containsKey('data') || data['data'] is! Map) {
throw Exception( throw Exception(
"Invalid response format: 'data' field is missing or not a List"); "Invalid response format: 'data' field is missing or not a Map");
} }
final List<Map<String, dynamic>> listData = return Map<String, dynamic>.from(data['data']);
List<Map<String, dynamic>>.from(data['data']);
if (listData.isEmpty) {
throw Exception("No department found with ID $id");
}
return listData[0];
} catch (e) { } catch (e) {
throw Exception('Error parsing response: $e'); throw Exception('Error parsing response: $e');
} }
@ -997,7 +1004,6 @@ class ApiService {
false; // Default to false if dismissed false; // Default to false if dismissed
} }
Future<Map<String, dynamic>> getCostCenterDetailsFind(int id) async { Future<Map<String, dynamic>> getCostCenterDetailsFind(int id) async {
final String apiUrldata = '$apiUrl/api/findCostCenter?cost_center_id=$id'; final String apiUrldata = '$apiUrl/api/findCostCenter?cost_center_id=$id';
@ -1042,5 +1048,4 @@ class ApiService {
throw Exception('Failed to load CostCenter details'); throw Exception('Failed to load CostCenter details');
} }
} }
} }