templateForex file

This commit is contained in:
venba-Inspriron-3558 2025-08-11 09:36:58 +05:30
parent d29caf66c5
commit d22e8bfcac
2 changed files with 1347 additions and 104 deletions

View File

@ -1,4 +1,6 @@
import 'dart:convert'; import 'dart:convert';
import 'dart:html' as html;
import 'dart:async';
import 'dart:io' as io show Directory, File; import 'dart:io' as io show Directory, File;
import 'package:delta_to_html/delta_to_html.dart'; import 'package:delta_to_html/delta_to_html.dart';
import 'package:flutter/cupertino.dart' as dom; import 'package:flutter/cupertino.dart' as dom;
@ -15,6 +17,9 @@ import 'package:frontend/Screens/myTemplates/templateForex.dart'
as _editorScrollController; as _editorScrollController;
import 'package:frontend/Screens/myTemplates/templateForex.dart' as _controller; import 'package:frontend/Screens/myTemplates/templateForex.dart' as _controller;
import 'package:html2md/html2md.dart' as html2md; import 'package:html2md/html2md.dart' as html2md;
import 'package:http_parser/http_parser.dart';
import 'package:image_picker/image_picker.dart';
import 'package:mime/mime.dart';
import 'package:vsc_quill_delta_to_html/vsc_quill_delta_to_html.dart'; import 'package:vsc_quill_delta_to_html/vsc_quill_delta_to_html.dart';
import 'package:flutter_quill/flutter_quill.dart' as quill; import 'package:flutter_quill/flutter_quill.dart' as quill;
@ -59,6 +64,8 @@ class TemplateForex extends StatefulWidget {
class TemplateForexState extends State<TemplateForex> { class TemplateForexState extends State<TemplateForex> {
final ApiService apiService = ApiService(); final ApiService apiService = ApiService();
Uint8List? _imageBytes;
String? selectedOrglogo;
// final QuillController _controller = QuillController.basic(); // final QuillController _controller = QuillController.basic();
String? orgId; String? orgId;
String? userId; String? userId;
@ -91,11 +98,6 @@ class TemplateForexState extends State<TemplateForex> {
"body_html": DeltaToHTML.encodeJson( "body_html": DeltaToHTML.encodeJson(
_controller.document.toDelta().toJson(), _controller.document.toDelta().toJson(),
), ),
// "body_html": jsonEncode(_controller.document.toDelta().toJson()),
// "body_html": _controller,
// "body_html": convertQuillDocToHtml(_controller.document),
// convert delta to HTML
"placeholder": jsonEncode(placeholderList), "placeholder": jsonEncode(placeholderList),
// "created_by": userId // "created_by": userId
}; };
@ -363,7 +365,7 @@ class TemplateForexState extends State<TemplateForex> {
print( print(
"API Selected User Has - ${widget.templateData?["templateData"]?["subject"]}", "API Selected User Has - ${widget.templateData?["templateData"]?["subject"]}",
); );
setState(() { setState(() async {
// Wrap in setState to update the UI // Wrap in setState to update the UI
controllers["templateName"]?.text = controllers["templateName"]?.text =
widget.templateData?["templateData"]?["template_name"] ?? ""; widget.templateData?["templateData"]?["template_name"] ?? "";
@ -432,7 +434,7 @@ class TemplateForexState extends State<TemplateForex> {
) ?? ) ??
0; 0;
print("Fetched template_id: $templateId"); print("Fetched template_id: $templateId");
fetchSignature();
// if (widget.group?["international_policy_id"] != null) { // if (widget.group?["international_policy_id"] != null) {
// selectedInternational = // selectedInternational =
// widget.group!["international_policy_id"].toString(); // widget.group!["international_policy_id"].toString();
@ -443,6 +445,34 @@ class TemplateForexState extends State<TemplateForex> {
} }
} }
Future<void> fetchSignature() async {
final uri = Uri.parse('$apiUrl/api/getForexSignaturePath');
final token = await getToken();
final response = await http.get(
uri,
headers: {'Authorization': 'Bearer $token'},
);
if (response.statusCode == 200) {
print("ERS - $response");
final json = jsonDecode(response.body);
print("ERSjson - $json");
String? rawLogoPath = json['url']?.toString();
if (rawLogoPath != null && rawLogoPath.isNotEmpty) {
print("ERSrawLogoPath - $rawLogoPath");
setState(() {
selectedOrglogo = rawLogoPath;
});
}
} else {
print("❌ Failed to fetch signature: ${response.statusCode}");
}
}
Future<void> handleSubmit() async { Future<void> handleSubmit() async {
Map<String, dynamic> data = TemplateData; Map<String, dynamic> data = TemplateData;
@ -492,6 +522,7 @@ class TemplateForexState extends State<TemplateForex> {
headers: { headers: {
'Authorization': 'Bearer $token', 'Authorization': 'Bearer $token',
'Content-Type': 'application/json', 'Content-Type': 'application/json',
// 'app-signature': 'ts-traveltool-2025-signature-123456',
}, },
body: jsonEncode(policyData), // Convert map to JSON body: jsonEncode(policyData), // Convert map to JSON
); );
@ -519,6 +550,70 @@ class TemplateForexState extends State<TemplateForex> {
} }
} }
Future<void> _pickImage() async {
final picker = ImagePicker();
final XFile? pickedFile = await picker.pickImage(
source: ImageSource.gallery,
);
if (pickedFile != null && kIsWeb) {
try {
final bytes = await pickedFile.readAsBytes();
print('✅ Image loaded, size: ${bytes.length} bytes');
setState(() {
_imageBytes = bytes;
});
await uploadSignature();
} catch (e) {
print('❌ Error reading image bytes: $e');
}
} else {
print('⚠️ Image picking canceled or not on web.');
}
}
Future<void> uploadSignature() async {
if (_imageBytes == null) {
print('⚠️ No image selected');
return;
}
final token = await getToken(); // Fetch token
if (token == null) {
throw Exception('Token not found. Please log in.');
}
final uri = Uri.parse('$apiUrl/api/forex_signature_upload');
final request = http.MultipartRequest('POST', uri);
// Add auth header
request.headers['Authorization'] = 'Bearer $token';
// Add the image as multipart with the key "signature"
request.files.add(
http.MultipartFile.fromBytes(
'signature', // <-- key name
_imageBytes!, // <-- image bytes
filename: 'signature.png', // <-- filename (can be png/jpg)
contentType: MediaType('image', 'png'),
),
);
try {
final response = await request.send();
final respStr = await response.stream.bytesToString();
if (response.statusCode == 200 || response.statusCode == 201) {
print('✅ Upload successful: $respStr');
} else {
print('❌ Upload failed (${response.statusCode}): $respStr');
}
} catch (e) {
print('❌ Error uploading signature: $e');
}
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return ResponsiveBuilder( return ResponsiveBuilder(
@ -683,56 +778,65 @@ class TemplateForexState extends State<TemplateForex> {
width: isDesktop ? MediaQuery.of(context).size.width * 0.8 : null, width: isDesktop ? MediaQuery.of(context).size.width * 0.8 : null,
child: IconTheme( child: IconTheme(
data: IconThemeData(size: 18), // Set icon size here data: IconThemeData(size: 18), // Set icon size here
child: QuillSimpleToolbar(
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( child: Container(
TextSelection.collapsed( color: Color(0xFFFFFEF0),
offset: _controller.selection.extentOffset + 1, width: isDesktop ? MediaQuery.of(context).size.width * 0.8 : null,
), child: IconTheme(
ChangeSource.local, data: IconThemeData(size: 18), // Set icon size here
); child: QuillSimpleToolbar(controller: _controller),
},
),
],
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;
},
), ),
), ),
// child: QuillSimpleToolbar(
// 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;
// },
// ),
// ),
// ),
// ),
), ),
), ),
), SizedBox(height: 2),
),
Container( Container(
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.end, mainAxisAlignment: MainAxisAlignment.end,
@ -782,9 +886,10 @@ class TemplateForexState extends State<TemplateForex> {
], ],
), ),
), ),
Container( Container(
padding: const EdgeInsets.all(16), padding: const EdgeInsets.all(16),
height: MediaQuery.of(context).size.height * 0.45, height: MediaQuery.of(context).size.height * 0.38,
decoration: BoxDecoration( decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10), borderRadius: BorderRadius.circular(10),
border: Border.all(color: Color(0xFFD6D5E6), width: 0.5), border: Border.all(color: Color(0xFFD6D5E6), width: 0.5),
@ -799,15 +904,16 @@ class TemplateForexState extends State<TemplateForex> {
padding: const EdgeInsets.all(16), padding: const EdgeInsets.all(16),
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 // if (imageUrl.startsWith('data:image')) {
if (imageUrl.startsWith('assets/')) { // return MemoryImage(
return AssetImage(imageUrl); // base64Decode(imageUrl.split(',').last),
} // );
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
@ -820,6 +926,58 @@ class TemplateForexState extends State<TemplateForex> {
), ),
), ),
), ),
SizedBox(height: 4),
Container(
child: Row(
// mainAxisAlignment: MainAxisAlignment.end,
children: [
Text(
"Upload Signature",
style: GoogleFonts.poppins(fontSize: 11.5),
),
SizedBox(width: 5),
GestureDetector(
onTap: _pickImage,
child:
_imageBytes != null
? ClipOval(
child: Image.memory(
_imageBytes!,
// width: 50,
// height: 50,
width: 50, // Use responsive width
height: 50,
fit: BoxFit.cover,
),
)
: selectedOrglogo != null
? ClipRect(
child: Image.network(
selectedOrglogo!,
width: 50, // Use responsive width
height: 50,
// width: 250,
// height: 55,
fit: BoxFit.contain,
errorBuilder: (context, error, stackTrace) {
return const CircleAvatar(
radius: 20,
backgroundColor: Colors.redAccent,
child: Icon(Icons.error, size: 10),
);
},
),
)
: const CircleAvatar(
radius: 20,
backgroundColor: Colors.amber,
child: Icon(Icons.add_a_photo, size: 10),
),
),
],
),
),
], ],
); );
} }

File diff suppressed because it is too large Load Diff