Merge branch 'main' of bitbucket.org:venbainformationtechnology/ts-tat into main
This commit is contained in:
commit
3474a1dbca
@ -325,7 +325,7 @@ class _TravelAgentListPlansState extends State<TravelAgentListPlans> {
|
||||
Row(
|
||||
children: [
|
||||
Text(
|
||||
'My Trips',
|
||||
'Trips',
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: isDesktop ? 16 : 14,
|
||||
fontWeight: FontWeight.w600,
|
||||
|
||||
@ -12,6 +12,7 @@ import 'package:flutter_localizations/flutter_localizations.dart';
|
||||
import 'package:flutter_quill/flutter_quill_internal.dart';
|
||||
import 'package:flutter_quill/quill_delta.dart';
|
||||
import 'package:flutter_quill_extensions/flutter_quill_extensions.dart';
|
||||
import 'package:frontend/Screens/myTemplates/quill_delta_sample.dart';
|
||||
import 'package:google_fonts/google_fonts.dart';
|
||||
import 'package:path/path.dart' as path;
|
||||
import 'package:responsive_builder/responsive_builder.dart';
|
||||
@ -22,11 +23,6 @@ import '../../services/apiService.dart';
|
||||
import '../../utils/auth_utils.dart';
|
||||
import '../../widgets/custom_user_travel.dart';
|
||||
|
||||
/// Custom Embed Definition
|
||||
class TimeStampEmbed {
|
||||
static const String type = 'timeStamp';
|
||||
}
|
||||
|
||||
class Template extends StatefulWidget {
|
||||
@override
|
||||
TemplateState createState() => TemplateState();
|
||||
@ -35,23 +31,27 @@ class Template extends StatefulWidget {
|
||||
class TemplateState extends State<Template> {
|
||||
final ApiService apiService = ApiService();
|
||||
|
||||
final FocusNode _editorFocusNode = FocusNode();
|
||||
final ScrollController _editorScrollController = ScrollController();
|
||||
final QuillController _controller = QuillController.basic();
|
||||
Color layoutColor = Colors.redAccent;
|
||||
Color bodyColor = Colors.white;
|
||||
|
||||
QuillController _controller = QuillController.basic();
|
||||
final FocusNode _focusNode = FocusNode();
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_controller = QuillController.basic(); // starts with empty document
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
_editorFocusNode.requestFocus(); // ✅ Ensure focus is requested
|
||||
});
|
||||
// _controller.document = Document.fromJson(kQuillDefaultSample);
|
||||
loadInitialData();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_focusNode.dispose();
|
||||
_controller.dispose();
|
||||
_editorScrollController.dispose();
|
||||
_editorFocusNode.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@ -185,30 +185,131 @@ class TemplateState extends State<Template> {
|
||||
controller: _controller,
|
||||
config: QuillSimpleToolbarConfig(
|
||||
embedButtons: FlutterQuillEmbeds.toolbarButtons(),
|
||||
showClipboardPaste: true,
|
||||
customButtons: [
|
||||
QuillToolbarCustomButtonOptions(
|
||||
icon: const Icon(Icons.add_alarm_rounded),
|
||||
onPressed: () {
|
||||
_controller.document.insert(
|
||||
_controller.selection.extentOffset,
|
||||
TimeStampEmbed(
|
||||
DateTime.now().toString(),
|
||||
),
|
||||
);
|
||||
|
||||
_controller.updateSelection(
|
||||
TextSelection.collapsed(
|
||||
offset: _controller.selection.extentOffset + 1,
|
||||
),
|
||||
ChangeSource.local,
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
buttonOptions: QuillSimpleToolbarButtonOptions(
|
||||
base: QuillToolbarBaseButtonOptions(
|
||||
afterButtonPressed: () {
|
||||
final isDesktop = {
|
||||
TargetPlatform.linux,
|
||||
TargetPlatform.windows,
|
||||
TargetPlatform.macOS
|
||||
}.contains(defaultTargetPlatform);
|
||||
if (isDesktop) {
|
||||
_editorFocusNode.requestFocus();
|
||||
}
|
||||
},
|
||||
),
|
||||
linkStyle: QuillToolbarLinkStyleButtonOptions(
|
||||
validateLink: (link) {
|
||||
// Treats all links as valid. When launching the URL,
|
||||
// `https://` is prefixed if the link is incomplete (e.g., `google.com` → `https://google.com`)
|
||||
// however this happens only within the editor.
|
||||
return true;
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
|
||||
// ✅ Modern editor
|
||||
// Container(
|
||||
// height: 300,
|
||||
// decoration: BoxDecoration(
|
||||
// border: Border.all(color: Colors.grey),
|
||||
// borderRadius: BorderRadius.circular(8),
|
||||
// ),
|
||||
// child: QuillEditor(
|
||||
// focusNode: _focusNode,
|
||||
// scrollController: ScrollController(),
|
||||
// controller: _controller,
|
||||
// config: QuillEditorConfig(
|
||||
// padding: const EdgeInsets.all(8),
|
||||
// embedBuilders: FlutterQuillEmbeds.editorBuilders(),
|
||||
// sharedConfigurations: const QuillSharedConfigurations(
|
||||
// locale: Locale('en'),
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
Container(
|
||||
height: 300,
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(color: Colors.grey),
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
child: QuillEditor.basic(
|
||||
focusNode: _editorFocusNode,
|
||||
scrollController: _editorScrollController,
|
||||
controller: _controller,
|
||||
// readOnly: true,
|
||||
config: QuillEditorConfig(
|
||||
requestKeyboardFocusOnCheckListChanged: false,
|
||||
// readOnlyMouseCursor: SystemMouseCursors.text,
|
||||
enableScribble: true,
|
||||
|
||||
padding: const EdgeInsets.all(8),
|
||||
placeholder: 'Type something...',
|
||||
embedBuilders: [
|
||||
...FlutterQuillEmbeds.editorBuilders(
|
||||
imageEmbedConfig: QuillEditorImageEmbedConfig(
|
||||
imageProviderBuilder: (context, imageUrl) {
|
||||
// https://pub.dev/packages/flutter_quill_extensions#-image-assets
|
||||
if (imageUrl.startsWith('assets/')) {
|
||||
return AssetImage(imageUrl);
|
||||
}
|
||||
return null;
|
||||
},
|
||||
),
|
||||
videoEmbedConfig: QuillEditorVideoEmbedConfig(
|
||||
customVideoBuilder: (videoUrl, readOnly) {
|
||||
// To load YouTube videos https://github.com/singerdmx/flutter-quill/releases/tag/v10.8.0
|
||||
return null;
|
||||
},
|
||||
),
|
||||
),
|
||||
TimeStampEmbedBuilder(),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class TimeStampEmbed extends Embeddable {
|
||||
const TimeStampEmbed(
|
||||
String value,
|
||||
) : super(timeStampType, value);
|
||||
|
||||
static const String timeStampType = 'timeStamp';
|
||||
|
||||
static TimeStampEmbed fromDocument(Document document) =>
|
||||
TimeStampEmbed(jsonEncode(document.toDelta().toJson()));
|
||||
|
||||
Document get document => Document.fromJson(jsonDecode(data));
|
||||
}
|
||||
|
||||
class TimeStampEmbedBuilder extends EmbedBuilder {
|
||||
@override
|
||||
String get key => 'timeStamp';
|
||||
|
||||
@override
|
||||
String toPlainText(Embed node) {
|
||||
return node.value.data;
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(
|
||||
BuildContext context,
|
||||
EmbedContext embedContext,
|
||||
) {
|
||||
return Row(
|
||||
children: [
|
||||
const Icon(Icons.access_time_rounded),
|
||||
Text(embedContext.node.value.data as String),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
46
lib/app.dart
46
lib/app.dart
@ -23,6 +23,7 @@ import 'package:flutter_localizations/flutter_localizations.dart';
|
||||
import 'package:flutter_quill/flutter_quill.dart' hide Text;
|
||||
import 'dart:html' as html;
|
||||
import 'package:frontend/config/apiUrl.dart'; // 1 newly added
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:http/http.dart' as http; // 2 newly added
|
||||
import 'dart:convert'; // 3 newly added
|
||||
|
||||
@ -45,7 +46,7 @@ class _MyAppState extends State<MyApp> {
|
||||
SemanticsBinding.instance.ensureSemantics(); // ✅ Safe here
|
||||
if (kIsWeb) {
|
||||
final uri = Uri.parse(html.window.location.href);
|
||||
if (uri.path == '/authredirection' &&
|
||||
if (uri.path == '/tstat/authredirection' &&
|
||||
uri.queryParameters['code'] != null) {
|
||||
_authCode = uri.queryParameters['code'];
|
||||
// _isAuthRedirect = true;
|
||||
@ -53,51 +54,50 @@ class _MyAppState extends State<MyApp> {
|
||||
// print(">>> _isAuthRedirect: $_isAuthRedirect");
|
||||
print(">>> Auth code found at startup: $_authCode");
|
||||
|
||||
// You can now:
|
||||
// - call an API
|
||||
// - store this in a Provider
|
||||
// - or just pass it through GoRouter as usual
|
||||
|
||||
// if(_authCode){
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
handleTokenUsingMS(_authCode);
|
||||
// }else{
|
||||
// _isAuthRedirect = false;
|
||||
// }
|
||||
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> handleTokenUsingMS(_authCode) async {
|
||||
Future<void> handleTokenUsingMS(authCode) async {
|
||||
if (authCode == null) return;
|
||||
|
||||
final url = '$apiUrl/auth/auth/verifyMSAuthUser?code=$_authCode';
|
||||
final url = '$apiUrl/auth/verifyMSAuthUser?code=$authCode';
|
||||
try {
|
||||
final response = await http.get(
|
||||
Uri.parse(url),
|
||||
headers: { 'Content-Type': 'application/json' }
|
||||
);
|
||||
final response = await http
|
||||
.get(Uri.parse(url), headers: {'Content-Type': 'application/json'});
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
final MS_Token = json.decode(response.body)['token'];
|
||||
print("MS_Token - $MS_Token");
|
||||
|
||||
if(MS_Token != ''){
|
||||
if (MS_Token != '') {
|
||||
print('Microsoft - Token Available');
|
||||
await storeUserDetails(MS_Token);
|
||||
}else{
|
||||
|
||||
print("userRole - $userRole");
|
||||
|
||||
if (userRole == "Travel Agent") {
|
||||
router.go('/listTravelAgentPlan');
|
||||
} else if (userRole == "Org Admin" || userRole == "Travel Admin") {
|
||||
router.go('/listAllPlan');
|
||||
} else {
|
||||
router.go('/listPlan');
|
||||
}
|
||||
} else {
|
||||
print('Microsoft - Token Not Available');
|
||||
throw Exception('Token not Founded');
|
||||
}
|
||||
}else{
|
||||
} else {
|
||||
final errorMessage = json.decode(response.body)['message'];
|
||||
print(errorMessage);
|
||||
throw Exception(errorMessage);
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
} catch (e) {
|
||||
print("Error: $e");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Future<void> storeUserDetails(String token) async {
|
||||
|
||||
@ -277,7 +277,7 @@ class _CustomAppBarState extends State<CustomAppBar> {
|
||||
|
||||
if (userData?["role"] == "Travel Agent")
|
||||
buildNavItem(
|
||||
"My Trips",
|
||||
"Trips",
|
||||
() => handleTabChange(
|
||||
TabSelection.myTrips, '/listTravelAgentPlan'),
|
||||
layoutColor!,
|
||||
|
||||
Loading…
Reference in New Issue
Block a user