diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 78567db..52fe383 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -30,8 +30,33 @@ - + + + + + + + + + + + + + + + + + + + diff --git a/lib/Utils/Common/MainController.dart b/lib/Utils/Common/MainController.dart index 8dfdb71..1e0f997 100644 --- a/lib/Utils/Common/MainController.dart +++ b/lib/Utils/Common/MainController.dart @@ -10,7 +10,7 @@ class MainController extends GetxController { var currentTab = [ const HomeScreen(), const ShortTrade(), - const Holdings(), + const Portfolio(), ].obs; void updateTab(int index) { diff --git a/lib/Utils/Common/custom_drop_down.dart b/lib/Utils/Common/custom_drop_down.dart index 11ecc49..1fd63cb 100644 --- a/lib/Utils/Common/custom_drop_down.dart +++ b/lib/Utils/Common/custom_drop_down.dart @@ -1,12 +1,19 @@ +import 'dart:math'; + import 'package:flutter/material.dart'; import 'package:get/get.dart'; +import 'package:traderscircuit/controller/risk_profile_controller.dart'; import '../text.dart'; class CustomDropDownWidget extends StatefulWidget { const CustomDropDownWidget( - {super.key, required this.header, required this.listData}); + {super.key, + required this.header, + required this.title, + required this.listData}); final String header; + final String title; final List listData; @override @@ -16,6 +23,27 @@ class CustomDropDownWidget extends StatefulWidget { class _CustomDropDownWidgetState extends State { RxBool onDropTap = false.obs; RxString selectedValue = "".obs; + RiskProfileController riskProfileController = + Get.put(RiskProfileController()); + + void updateOrAddData(String key, String value) { + bool keyExists = false; + for (int i = 0; i < riskProfileController.selectedData.length; i++) { + Map item = riskProfileController.selectedData[i]; + if (item.containsKey(key)) { + riskProfileController.selectedData[i][key] = + value; // Update existing value + keyExists = true; + break; + } + } + + if (!keyExists) { + // Add new key-value pair + riskProfileController.selectedData.add({key: value}); + } + } + @override Widget build(BuildContext context) { return Obx( @@ -146,6 +174,8 @@ class _CustomDropDownWidgetState extends State { onTap: () { selectedValue.value = widget.listData[index]; onDropTap.value = !onDropTap.value; + updateOrAddData( + widget.title, widget.listData[index]); }, child: Column( crossAxisAlignment: CrossAxisAlignment.start, diff --git a/lib/Utils/api_urls.dart b/lib/Utils/api_urls.dart index 0dc8680..c73a34b 100644 --- a/lib/Utils/api_urls.dart +++ b/lib/Utils/api_urls.dart @@ -1,4 +1,8 @@ class ApiUrls { +// PIE BASE URL FOR SMALL CASE --> NEED TO BE UPDATED + + static const String pieBase = "https://app.piadvisors.in/"; + //Base URL static const base = "http://192.168.50.82/Trader_circuit/api/"; @@ -22,4 +26,8 @@ class ApiUrls { //FAQ API static String faqApi = "${base}getFaq"; + + //RISK PROFILE API + static String getRiskProfileQuestionAnswerApi = "${base}riskProfileQueAns"; + static String addRiskProfileQuestionAnswerApi = "${base}addUserRiskProfile"; } diff --git a/lib/controller/risk_profile_controller.dart b/lib/controller/risk_profile_controller.dart new file mode 100644 index 0000000..732e1cb --- /dev/null +++ b/lib/controller/risk_profile_controller.dart @@ -0,0 +1,9 @@ +import 'package:get/get.dart'; + +import '../model/RiskProfileModel/risk_profile_ques_answer_model.dart'; + +class RiskProfileController extends GetxController { + RiskProfileQuestionAnswerModel riskProfileQuestionAnswerModel = + RiskProfileQuestionAnswerModel(); + List> selectedData = []; +} diff --git a/lib/data/network/network_api_services.dart b/lib/data/network/network_api_services.dart index 785672e..513c5d0 100644 --- a/lib/data/network/network_api_services.dart +++ b/lib/data/network/network_api_services.dart @@ -16,7 +16,7 @@ class NetworkApiServices extends BaseApiServices { base64.encode( utf8.encode('traderCircuitUser:71%@L%es^bUX94`J9XT*@bh,._WWM{')); @override - Future getApi(String url) async { + Future getApi(String url, {bool isAuth = false}) async { if (kDebugMode) { print("api url is >>> $url"); } @@ -25,14 +25,17 @@ class NetworkApiServices extends BaseApiServices { String? token = prefs.getString('accessToken').toString(); log(token); try { - response = await dio.get( - url, - // options: Options(headers: { - // 'authorization': "Bearer $token", - - // // "device-id": deviceId - // }) - ); + response = await dio.get(url, + options: (token == null || token == "") + ? Options( + headers: { + "Authorization": basicAuth, + }, + ) + : Options(headers: { + "Authorization": basicAuth, + 'access-token': token, + })); if (response.statusCode == 200) { return ResponseData( @@ -61,7 +64,7 @@ class NetworkApiServices extends BaseApiServices { } @override - Future postApi(data, String url) async { + Future postApi(data, String url, {bool isAuth = false}) async { if (kDebugMode) { print("data >>> $data"); print("api url is >>> $url"); diff --git a/lib/main.dart b/lib/main.dart index f56d010..9624b71 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -7,6 +7,7 @@ import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:get/get.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:traderscircuit/firebase_options.dart'; +import 'package:scgateway_flutter_plugin/scgateway_flutter_plugin.dart'; import 'package:traderscircuit/resources/routes/route_name.dart'; import 'package:firebase_core/firebase_core.dart'; import 'package:traderscircuit/resources/routes/routes.dart'; @@ -28,6 +29,14 @@ Future main() async { // GlobalVariables globalVariables = GlobalVariables(); //token = prefs.getString('token'); // OnBoard = prefs.getBool("OnBoard"); + + //smallcase + ScgatewayFlutterPlugin.setConfigEnvironment( + GatewayEnvironment.PRODUCTION, + 'pi-advisors', + false, + [], + ); SystemChrome.setPreferredOrientations([ DeviceOrientation.portraitUp, ]).then((value) => runApp(const MyApp())); diff --git a/lib/model/RiskProfileModel/risk_profile_ques_answer_model.dart b/lib/model/RiskProfileModel/risk_profile_ques_answer_model.dart new file mode 100644 index 0000000..e3382fa --- /dev/null +++ b/lib/model/RiskProfileModel/risk_profile_ques_answer_model.dart @@ -0,0 +1,123 @@ +class RiskProfileQuestionAnswerModel { + String? status; + int? statusCode; + String? message; + List? data; + + RiskProfileQuestionAnswerModel( + {this.status, this.statusCode, this.message, this.data}); + + RiskProfileQuestionAnswerModel.fromJson(Map json) { + status = json['status']; + statusCode = json['status_code']; + message = json['message']; + if (json['data'] != null) { + data = []; + json['data'].forEach((v) { + data!.add(Data.fromJson(v)); + }); + } + } + + Map toJson() { + final Map data = {}; + data['status'] = status; + data['status_code'] = statusCode; + data['message'] = message; + if (this.data != null) { + data['data'] = this.data!.map((v) => v.toJson()).toList(); + } + return data; + } +} + +class Data { + int? id; + String? question; + String? isActive; + + String? createdAt; + String? updatedAt; + List? answer; + + Data( + {this.id, + this.question, + this.isActive, + this.createdAt, + this.updatedAt, + this.answer}); + + Data.fromJson(Map json) { + id = json['id']; + question = json['question']; + isActive = json['is_active']; + + createdAt = json['created_at']; + updatedAt = json['updated_at']; + if (json['answer'] != null) { + answer = []; + json['answer'].forEach((v) { + answer!.add(Answer.fromJson(v)); + }); + } + } + + Map toJson() { + final Map data = {}; + data['id'] = id; + data['question'] = question; + data['is_active'] = isActive; + + data['created_at'] = createdAt; + data['updated_at'] = updatedAt; + if (answer != null) { + data['answer'] = answer!.map((v) => v.toJson()).toList(); + } + return data; + } +} + +class Answer { + int? id; + int? questionId; + String? answer; + int? points; + String? isActive; + + String? createdAt; + String? updatedAt; + + Answer( + {this.id, + this.questionId, + this.answer, + this.points, + this.isActive, + this.createdAt, + this.updatedAt}); + + Answer.fromJson(Map json) { + id = json['id']; + questionId = json['question_id']; + answer = json['answer']; + points = json['points']; + isActive = json['is_active']; + + createdAt = json['created_at']; + updatedAt = json['updated_at']; + } + + Map toJson() { + final Map data = {}; + data['id'] = id; + data['question_id'] = questionId; + data['answer'] = answer; + data['points'] = points; + data['is_active'] = isActive; + + data['created_at'] = createdAt; + data['updated_at'] = updatedAt; + return data; + } +} diff --git a/lib/model/SmallCaseModel/broker_account_model.dart b/lib/model/SmallCaseModel/broker_account_model.dart new file mode 100644 index 0000000..16b1a4e --- /dev/null +++ b/lib/model/SmallCaseModel/broker_account_model.dart @@ -0,0 +1,34 @@ +class BrokerAccountModel { + final String? id; + final String? userId; + final String? brokerName; + final String? authToken; + final String? txnId; + + const BrokerAccountModel({ + required this.id, + required this.userId, + required this.brokerName, + required this.authToken, + required this.txnId, + }); + + factory BrokerAccountModel.fromJson(Map json) { + return BrokerAccountModel( + id: json['id'].toString(), + userId: json['user_id'].toString(), + brokerName: json['broker_name'] as String?, + authToken: json['auth_token'] as String?, + txnId: json['transaction_id'] as String?, + ); + } + + Map toJson() { + final Map data = {}; + data['user_id'] = userId; + data['broker_name'] = brokerName; + data['auth_token'] = authToken; + data['transaction_id'] = txnId; + return data; + } +} diff --git a/lib/view/MainScreen/Portfolio/PortfolioEmpty.dart b/lib/view/MainScreen/Portfolio/PortfolioEmpty.dart index 72244f6..cff2cdd 100644 --- a/lib/view/MainScreen/Portfolio/PortfolioEmpty.dart +++ b/lib/view/MainScreen/Portfolio/PortfolioEmpty.dart @@ -1,14 +1,23 @@ +import 'dart:async'; +import 'dart:convert'; + +import 'package:async/async.dart'; import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:get/get.dart'; import 'package:lottie/lottie.dart'; +import 'package:scgateway_flutter_plugin/scgateway_flutter_plugin.dart'; import 'package:traderscircuit/Utils/Common/CommonBottomNavigation.dart'; import 'package:traderscircuit/Utils/Common/commonBotton.dart'; import 'package:traderscircuit/Utils/text.dart'; import 'package:traderscircuit/view/MainScreen/MainScreen.dart'; +import 'package:traderscircuit/view/MainScreen/Portfolio/Holdings.dart'; import 'package:traderscircuit/view/Sidemenu/Sidemenu.dart'; import 'package:traderscircuit/view/onBoarding/splashScreen1.dart'; +import '../../../model/SmallCaseModel/broker_account_model.dart'; +import '../../../view_model/SmallCaseApi/smallcase_api_methods.dart'; + class Portfolio extends StatefulWidget { const Portfolio({super.key}); @@ -20,13 +29,238 @@ class _PortfolioState extends State { GlobalKey _scaffoldKey1 = GlobalKey(); List containerTexts = ["Swing Trade", "Multibagger", "Options"]; final selectedIndex = 0.obs; + + FutureGroup fetchUserIdAndBrokerAccounts = FutureGroup(); + List myBrokerAccounts = []; + @override + void initState() { + // fetchUserIdAndBrokerAccounts.add(getUserId()); // TODO Need to add userid here + fetchUserIdAndBrokerAccounts.add(fetchBrokerAccounts()); + fetchUserIdAndBrokerAccounts.close(); + // fetchUserIdAndBrokerAccounts.future.then((value) { + // int userId = value[0]; + // List brokerAccounts = value[1]; + // try { + // myBrokerAccounts.addAll(brokerAccounts + // .where((element) => element.userId == userId.toString())); + // } catch (e) {} + // debugPrint("myBrokerAccounts.length ${myBrokerAccounts.length}"); + // debugPrint("BrokerAccounts.length ${brokerAccounts.length}"); + // if (myBrokerAccounts.isEmpty) { + // setState(() { + // body = Center( + // child: Column( + // mainAxisSize: MainAxisSize.min, + // children: [ + // const Text("You need to add broker account"), + // const Text("to fetch holdings"), + // const SizedBox(height: 6), + // OutlinedButton( + // onPressed: () { + // //Get.off(Broker()); + // Get.to(() => Broker()); + // }, + // child: const Text("Brokerage Account"), + // ) + // ], + // )); + // }); + // } else { + // setBodyToBrokers(); + // } + // }); + + super.initState(); + } + + // void setBodyToBrokers() { + // setState(() { + // body = Padding( + // padding: const EdgeInsets.only(top: 28, left: 28, right: 28), + // child: Column(mainAxisSize: MainAxisSize.min, children: [ + // const Text("Please select your broker account"), + // const SizedBox(height: 8), + // Expanded( + // child: ListView.builder( + // itemCount: myBrokerAccounts.length, + // itemBuilder: (context, index) { + // return OutlinedButton( + // onPressed: () { + // setState(() { + // body = const Center(child: CircularProgressIndicator()); + // }); + // fetchHoldingsImportTxnId( + // myBrokerAccounts.elementAt(index).authToken!) + // .then((txnIdResponse) { + // if (txnIdResponse.statusCode == 200) { + // debugPrint('SESSION STARTED'); + // debugPrint( + // 'AUTH TOKEN: ${myBrokerAccounts.elementAt(index).authToken!}'); + // fetchHoldingsImportTxnId( + // myBrokerAccounts.elementAt(index).authToken!) + // .then((txnRes) { + // String txnId = + // jsonDecode(txnRes.body)['data']['transactionId']; + // debugPrint('TXN ID $txnId'); + // ScgatewayFlutterPlugin.triggerGatewayTransaction( + // txnId) + // .then( + // (txnRes) { + // debugPrint('TXN RES $txnRes'); + // if (txnRes != null) { + // fetchHoldings( + // //holdingsAuthToken + // myBrokerAccounts + // .elementAt(index) + // .authToken!) + // .then( + // (holdings) { + // setState(() { + // // body = netWorthPage(holdings); + // }); + // }, + // ); + // } + // }, + // ); + // }); + // } else { + // debugPrint('SESSION EXPIRED'); + // onTxnTimeout(); + // } + // }); + // }, + // child: Text(myBrokerAccounts.elementAt(index).brokerName!), + // ); + // }, + // ), + // ) + // ]), + // ); + // }); + // } + + // void onTxnTimeout() { + // bool showDialogContent = true; + // bool replaceDialogContentWithLoader = false; + // showDialog( + // barrierDismissible: false, + // context: context, + // builder: (context) => AlertDialog(content: StatefulBuilder( + // builder: (context, setDialogState) { + // return Column( + // mainAxisSize: MainAxisSize.min, + // children: [ + // Visibility( + // visible: showDialogContent, + // child: Column( + // mainAxisSize: MainAxisSize.min, + // crossAxisAlignment: CrossAxisAlignment.start, + // children: [ + // const Text("Transaction Timeout", + // style: TextStyle( + // fontWeight: FontWeight.bold, + // fontSize: 18, + // )), + // const SizedBox(height: 18), + // const Text("You need to login again to continue"), + // const SizedBox(height: 18), + // Row( + // mainAxisAlignment: MainAxisAlignment.end, + // children: [ + // OutlinedButton( + // onPressed: () { + // setBodyToBrokers(); + // Get.back(); + // }, + // child: const Text("Cancel"), + // ), + // const SizedBox(width: 12), + // ElevatedButton( + // onPressed: () { + // setDialogState(() { + // showDialogContent = false; + // replaceDialogContentWithLoader = true; + // }); + // //login again + // fetchAuthToken().then((fetchedAuthToken) { + // debugPrint( + // "fetchedAuthToken $fetchedAuthToken"); + // fetchBrokerConnectTxnId( + // authToken: fetchedAuthToken) + // .then( + // (txnId) => + // ScgatewayFlutterPlugin.initGateway( + // fetchedAuthToken) + // .then( + // (value) => ScgatewayFlutterPlugin + // .triggerGatewayTransaction( + // txnId, + // ).then( + // (loginRes) { + // if (loginRes != null) { + // var data = + // jsonDecode(loginRes)['data']; + // if (data != null) { + // String authToken = jsonDecode( + // data)['smallcaseAuthToken']; + // String brokerName = + // jsonDecode(data)['broker']; + // String txnId = jsonDecode( + // data)['transactionId']; + // getUserId().then((userId) { + // postBrokerAccount( + // userId: userId! + // .toString(), + // brokerName: + // brokerName, + // authToken: authToken, + // txnId: txnId) + // .then((isPosted) { + // if (isPosted) { + // // Get.back(); + // // setBodyToBrokers(); + // Get.off(Holdings()); + // } + // }); + // }); + // } + // } + // }, + // ), + // ), + // ); + // }); + // }, + // child: const Text("Login Again"), + // ), + // ], + // ) + // ], + // ), + // ), + // Visibility( + // visible: replaceDialogContentWithLoader, + // child: const Padding( + // padding: EdgeInsets.symmetric(vertical: 28.0), + // child: Center( + // child: CircularProgressIndicator(), + // ), + // ), + // ) + // ], + // ); + // }, + // ))); + // } + @override Widget build(BuildContext context) { return Scaffold( key: _scaffoldKey1, backgroundColor: Colors.black, drawerEnableOpenDragGesture: false, - drawer: Container(child: SideMenu()), + drawer: Container(child: const SideMenu()), extendBody: true, appBar: AppBar( scrolledUnderElevation: 0.0, @@ -49,12 +283,13 @@ class _PortfolioState extends State { ), body: Stack( children: [ - CommonBlurLeft(), - CommonBlurRight(), + const CommonBlurLeft(), + const CommonBlurRight(), Stack( children: [ Padding( - padding: EdgeInsets.symmetric(horizontal: 16, vertical: 16), + padding: + const EdgeInsets.symmetric(horizontal: 16, vertical: 16), child: Column( children: [ Row( @@ -75,15 +310,73 @@ class _PortfolioState extends State { fontWeight: FontWeight.w400, ), ), - Spacer(), + const Spacer(), LottieBuilder.asset( "assets/images/empty.json", width: 200.w, height: 200.h, ), - Spacer(), - CommonBtn(text: "Add"), - Spacer(), + const Spacer(), + CommonBtn( + text: "Add", + onTap: () { + // replaceAddAccountBtnWithLoader(); + // Timer.periodic(Duration(seconds: 8), (timer) { + // // replaceLoaderWithAddAccountBtn(); + // timer.cancel(); + // }); + fetchAuthToken().then((fetchedAuthToken) { + debugPrint("fetchedAuthToken $fetchedAuthToken"); + fetchBrokerConnectTxnId(authToken: fetchedAuthToken) + .then( + (txnId) => ScgatewayFlutterPlugin.initGateway( + fetchedAuthToken) + .then( + (value) => ScgatewayFlutterPlugin + .triggerGatewayTransaction( + txnId, + ).then( + (loginRes) { + if (loginRes != null) { + var data = jsonDecode(loginRes)['data']; + if (data != null) { + String authToken = jsonDecode( + data)['smallcaseAuthToken']; + String brokerName = + jsonDecode(data)['broker']; + String txnId = + jsonDecode(data)['transactionId']; + // getUserId().then((userId) { + postBrokerAccount( + userId: "12", + brokerName: brokerName, + authToken: authToken, + txnId: txnId) + .then((isPosted) { + // replaceLoaderWithAddAccountBtn(); + // Navigator.pushReplacement( + // context, + // MaterialPageRoute( + // builder: (context) => + // Broker())); + ScaffoldMessenger.of(context) + .clearSnackBars(); + ScaffoldMessenger.of(context) + .showSnackBar(SnackBar( + content: Text( + 'New broker account is added'))); + }); + // }); + // replaceLoaderWithAddAccountBtn(); + } + } + }, + ), + ), + ); + }); + }), + const Spacer(), ], ), ), diff --git a/lib/view/Sidemenu/contactUs/create_ticket_bottom_sheet.dart b/lib/view/Sidemenu/contactUs/create_ticket_bottom_sheet.dart index ddbef8c..15ec852 100644 --- a/lib/view/Sidemenu/contactUs/create_ticket_bottom_sheet.dart +++ b/lib/view/Sidemenu/contactUs/create_ticket_bottom_sheet.dart @@ -68,6 +68,7 @@ class CreateTicketBottomSheet { "Content Buytes", "Market Insights" ], + title: "", ), const Gap(14), Stack( diff --git a/lib/view/login/Kyc.dart b/lib/view/login/Kyc.dart index aea9845..6257951 100644 --- a/lib/view/login/Kyc.dart +++ b/lib/view/login/Kyc.dart @@ -14,6 +14,7 @@ import 'package:traderscircuit/resources/routes/route_name.dart'; import 'package:traderscircuit/view/onBoarding/splashScreen1.dart'; import '../../controller/kyc_controller.dart'; +import '../../view_model/RiskProfileApi/risk_profile_api.dart'; class Kyc extends StatefulWidget { const Kyc({super.key}); diff --git a/lib/view/login/UpdateRiskProfile.dart b/lib/view/login/UpdateRiskProfile.dart index c1bfd49..e06be40 100644 --- a/lib/view/login/UpdateRiskProfile.dart +++ b/lib/view/login/UpdateRiskProfile.dart @@ -1,15 +1,21 @@ -import 'dart:ui'; +import 'dart:convert'; +import 'dart:developer'; +import 'package:dio/dio.dart'; import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; -import 'package:get/get.dart'; +import 'package:get/get.dart' hide FormData; import 'package:traderscircuit/Utils/Common/CommonAppbar.dart'; -import 'package:traderscircuit/Utils/Common/commonBotton.dart'; +import 'package:traderscircuit/Utils/dialogs.dart'; import 'package:traderscircuit/Utils/text.dart'; -import 'package:traderscircuit/resources/routes/route_name.dart'; +import 'package:traderscircuit/controller/risk_profile_controller.dart'; +import 'package:traderscircuit/model/RiskProfileModel/risk_profile_ques_answer_model.dart'; import 'package:traderscircuit/view/onBoarding/splashScreen1.dart'; +import '../../Utils/Common/commonBotton.dart'; import '../../Utils/Common/custom_drop_down.dart'; +import '../../resources/routes/route_name.dart'; +import '../../view_model/RiskProfileApi/risk_profile_api.dart'; class UpdateRiskProfile extends StatefulWidget { const UpdateRiskProfile({super.key}); @@ -19,6 +25,34 @@ class UpdateRiskProfile extends StatefulWidget { } class _UpdateRiskProfileState extends State { + RxBool isLoading = true.obs; + RiskProfileController riskProfileController = + Get.put(RiskProfileController()); + List questionIdList = []; + List answerIdList = []; + List>> dropHeader = []; + + @override + void initState() { + RiskProfileApi().getRiskProfileData().then((value) { + riskProfileController.riskProfileQuestionAnswerModel = + RiskProfileQuestionAnswerModel.fromJson(value.data); + for (var a + in riskProfileController.riskProfileQuestionAnswerModel.data!) { + List titleTxt = []; + titleTxt.clear(); + for (var b in a.answer!) { + titleTxt.add(b.answer!); + } + dropHeader.add({a.question!: titleTxt}); + } + + log(dropHeader.toString()); + isLoading.value = false; + }); + super.initState(); + } + @override Widget build(BuildContext context) { return Scaffold( @@ -28,125 +62,151 @@ class _UpdateRiskProfileState extends State { ), backgroundColor: Colors.black, extendBody: true, - body: Stack( - children: [ - const CommonBlurLeft(), - const CommonBlurRight(), - Stack( - children: [ - Padding( - padding: - const EdgeInsets.symmetric(horizontal: 16, vertical: 16), - child: ListView( - physics: const BouncingScrollPhysics(), - // mainAxisAlignment: MainAxisAlignment.start, - // crossAxisAlignment: CrossAxisAlignment.start, - - children: [ - updateRiskProfileData( - "What is your investment goal?", - "Select your goal", - ), - updateRiskProfileData( - "Add Investment Experience field", - "Select your Experience", - ), - updateRiskProfileData( - "What types of stocks do you prefer?", - "Select types of stock", - ), - updateRiskProfileData( - "What is your Risk Perception?", - "Select your Perception", - ), - updateRiskProfileData( - "What is your favoured Market Condition?", - "Select Condition", - ), - updateRiskProfileData( - "What is your Emotional Response to Market Volatility?", - "Choose your query", - ), - SizedBox( - height: 70.h, - ), - CommonBtn( - text: "Submit", - onTap: () { - Get.toNamed(RouteName.mainscreen); - }, - ), - SizedBox( - height: 10.h, - ), - ], + body: Obx( + () => isLoading.value + ? const Center( + child: CircularProgressIndicator( + color: Color(0xFF9A0000), ), + ) + : Stack( + children: [ + const CommonBlurLeft(), + const CommonBlurRight(), + Stack( + children: [ + Padding( + padding: const EdgeInsets.symmetric( + horizontal: 16, vertical: 16), + child: ListView.builder( + itemCount: riskProfileController + .riskProfileQuestionAnswerModel + .data! + .length + + 1, + itemBuilder: (ctx, index) { + return riskProfileController + .riskProfileQuestionAnswerModel + .data! + .length <= + index + ? Column( + children: [ + SizedBox( + height: 70.h, + ), + CommonBtn( + text: "Submit", + onTap: () { + questionIdList.clear(); + answerIdList.clear(); + if (riskProfileController + .riskProfileQuestionAnswerModel + .data! + .length != + riskProfileController + .selectedData.length) { + utils.showToast( + "All Fields Required"); + } else { + // Iterate through selected data and match with provided data + for (var entry + in riskProfileController + .selectedData) { + String question = + entry.keys.first; + String answer = + entry.values.first; + + // Find matching question + var questionMatch = + riskProfileController + .riskProfileQuestionAnswerModel + .data! + .firstWhere( + (item) => + item.question == + question, + ); + if (questionMatch != null) { + questionIdList + .add(questionMatch.id!); + } + + // Find matching answer + if (questionMatch != null) { + var answerMatch = + questionMatch.answer! + .firstWhere( + (ans) => + ans.answer == answer, + ); + if (answerMatch != null) { + answerIdList + .add(answerMatch.id!); + } + } + } + + RiskProfileApi() + .addRiskProfileData( + FormData.fromMap({ + "question_ids": jsonEncode( + questionIdList), + "answer_ids": + jsonEncode(answerIdList), + })) + .then((value) { + Map + responseData = + Map.from( + value.data); + utils.showToast( + responseData["message"]); + Get.toNamed( + RouteName.mainscreen); + }); + } + }, + ), + SizedBox( + height: 10.h, + ), + ], + ) + : updateRiskProfileData( + riskProfileController + .riskProfileQuestionAnswerModel + .data![index] + .question!, + "Select your goal", + index); + })), + ], + ), + ], ), - ], - ), - ], ), ); } -} -Widget updateRiskProfileData( - String tilte, - String headerText, -) { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - text18W400(tilte), - SizedBox( - height: 15.h, - ), - CustomDropDownWidget( - header: headerText, - listData: dropHeader[headerText]!, - ), - SizedBox( - height: 35.h, - ), - ], - ); + Widget updateRiskProfileData(String tilte, String headerText, int index) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + text18W400(tilte), + SizedBox( + height: 15.h, + ), + CustomDropDownWidget( + header: headerText, + listData: dropHeader[index][tilte]!, + title: tilte, + ), + SizedBox( + height: 35.h, + ), + ], + ); + } } - -Map> dropHeader = { - "Select your goal": [ - "Wealth Preservation", - "Capital Growth", - "Income Generation", - "Retirement Planning" - ], - "Select your Experience": [ - "No Experience", - "Beginner (0 - 3 months)", - "Intermediate (3 - 12 months)", - "Expert ( > 12 months)", - "Professional ( 3 - 5 years )" - ], - "Select types of stock": [ - "Swing Trade", - "Options", - "Multibagger", - "Long term", - ], - "Select your Perception": [ - "Very Conservative", - "Conservative", - "Moderate", - "Aggressive", - ], - "Select Condition": [ - "Bullish", - "Neutral", - "Bearish", - ], - "Choose your query": [ - "Calm", - "Neutral", - "Anxious", - "Stressed", - ], -}; diff --git a/lib/view_model/RiskProfileApi/risk_profile_api.dart b/lib/view_model/RiskProfileApi/risk_profile_api.dart new file mode 100644 index 0000000..3726185 --- /dev/null +++ b/lib/view_model/RiskProfileApi/risk_profile_api.dart @@ -0,0 +1,45 @@ +import 'dart:developer'; + +import 'package:dio/dio.dart'; + +import '../../Utils/api_urls.dart'; +import '../../Utils/base_manager.dart'; +import '../../data/network/network_api_services.dart'; + +class RiskProfileApi { + Future> getRiskProfileData() async { + final response = await NetworkApiServices() + .getApi(ApiUrls.getRiskProfileQuestionAnswerApi, isAuth: true); + log(response.data.toString()); + if (response.status == ResponseStatus.SUCCESS) { + Map responseData = + Map.from(response.data); + if (responseData['status'] == "success") { + return response; + } else { + return ResponseData( + responseData['message'], ResponseStatus.FAILED); + } + } + return response; + } + + Future> addRiskProfileData(FormData data) async { + final response = await NetworkApiServices().postApi( + data, + ApiUrls.addRiskProfileQuestionAnswerApi, + ); + log(response.data.toString()); + if (response.status == ResponseStatus.SUCCESS) { + Map responseData = + Map.from(response.data); + if (responseData['status'] == "success") { + return response; + } else { + return ResponseData( + responseData['message'], ResponseStatus.FAILED); + } + } + return response; + } +} diff --git a/lib/view_model/SmallCaseApi/smallcase_api_methods.dart b/lib/view_model/SmallCaseApi/smallcase_api_methods.dart new file mode 100644 index 0000000..4726b06 --- /dev/null +++ b/lib/view_model/SmallCaseApi/smallcase_api_methods.dart @@ -0,0 +1,137 @@ +import 'dart:convert'; +import 'package:flutter/material.dart'; +import 'package:http/http.dart' as http; +import 'package:scgateway_flutter_plugin/scgateway_flutter_plugin.dart'; + +import '../../Utils/api_urls.dart'; +import '../../model/SmallCaseModel/broker_account_model.dart'; + +// void openDashboardPage(BuildContext context) { +// Navigator.pushReplacement( +// context, MaterialPageRoute(builder: ((context) => PortfolioMainUI()))); +// } + +// void openEquityPage(BuildContext context, Map holdings) { +// Navigator.push( +// context, +// MaterialPageRoute( +// builder: ((context) => Equityinner(holdings: holdings)))); +// } + +//broker account table +//fetch broker accounts +Future> fetchBrokerAccounts() async { + final response = await http.Client() + .get(Uri.parse('${ApiUrls.pieBase}api/get_broker_account_data')); + final parsed = jsonDecode(response.body); + return parsed + .map((json) => BrokerAccountModel.fromJson(json)) + .toList(); +} + +//delete broker account +Future deleteBrokerAccount(int id) async { + final response = await http.Client() + .get(Uri.parse('${ApiUrls.pieBase}api/delete_brokerage_account/$id')); + if (response.statusCode == 200) return true; + return false; +} + +//post broker account +Future postBrokerAccount({ + required String userId, + required String brokerName, + required String authToken, + required String txnId, +}) async { + var response = await http.post( + Uri.parse('${ApiUrls.pieBase}api/add_broker_account'), + body: { + "user_id": userId, + "broker_name": brokerName, + "auth_token": authToken, + "transaction_id": txnId, + }, + ); + if (response.statusCode == 200) return true; + return false; +} + +Future fetchAuthToken() async { + var response = await http.get( + Uri.parse( + '${ApiUrls.pieBase}api/get_small_case_auth_token/', + ), + ); + return jsonDecode(response.body)['data']; +} + +Future fetchBrokerConnectTxnId({required String authToken}) async { + var response = await http.get( + Uri.parse( + '${ApiUrls.pieBase}api/get_small_case_broker_connect_transaction/$authToken', + ), + ); + return jsonDecode(response.body)['data']['transactionId']; +} + +Future fetchHoldingsImportTxnId(String authToken) async { + var response = await http.get( + Uri.parse( + '${ApiUrls.pieBase}api/get_small_case_holding_import_transaction_id/$authToken', + ), + ); + return response; +} + +Future> fetchHoldings(String authToken) async { + var response = await http.get( + Uri.parse( + '${ApiUrls.pieBase}api/fetch_small_case_holding/$authToken', + ), + ); + return jsonDecode(response.body)['data']; +} + +Future fetchStocksOrderTxnId(String authToken, String body) async { + var response = await http.post(Uri.parse( + '${ApiUrls.pieBase}api/create_post_transaction_stock_order?body=$body&auth_token=$authToken')); + var txnId = jsonDecode(response.body)['data']['transactionId']; + return txnId; +} + +enum TradeType { + BUY, + SELL, +} + +void loginNTrade(String ticker, int quantity, TradeType tradeType) { + fetchAuthToken().then((fetchedAuthToken) { + // debugPrint("fetchedAuthToken $fetchedAuthToken"); + fetchBrokerConnectTxnId(authToken: fetchedAuthToken).then( + (txnId) => ScgatewayFlutterPlugin.initGateway(fetchedAuthToken).then( + (value) => ScgatewayFlutterPlugin.triggerGatewayTransaction( + txnId, + ).then( + (loginRes) { + if (loginRes != null) { + var data = jsonDecode(loginRes)['data']; + if (data != null) { + String authToken = jsonDecode(data)['smallcaseAuthToken']; + String brokerName = jsonDecode(data)['broker']; + String txnId = jsonDecode(data)['transactionId']; + String body = + '{"intent":"TRANSACTION","orderConfig":{"type":"SECURITIES","securities":[{"ticker":"$ticker","quantity":"$quantity","type":"${tradeType.name}"},{"ticker":"RELIANCE","quantity":1,"type":"BUY"}]}}'; + fetchStocksOrderTxnId(authToken, body).then( + (stocksOrderTxnId) => ScgatewayFlutterPlugin + .triggerGatewayTransaction(stocksOrderTxnId) + .then( + (value) => debugPrint("Stocks Order res $value"))); + } + } + }, + ), + ), + ); + }); +} diff --git a/pubspec.lock b/pubspec.lock index 5b43aac..389bb18 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -26,7 +26,7 @@ packages: source: hosted version: "2.4.2" async: - dependency: transitive + dependency: "direct main" description: name: async sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" @@ -93,10 +93,10 @@ packages: dependency: transitive description: name: collection - sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a + sha256: f092b211a4319e98e5ff58223576de6c2803db36221657b46c82574721240687 url: "https://pub.dev" source: hosted - version: "1.18.0" + version: "1.17.2" connectivity_plus: dependency: "direct main" description: @@ -556,10 +556,10 @@ packages: dependency: transitive description: name: meta - sha256: a6e590c838b18133bb482a2745ad77c5bb7715fb0451209e1a7567d416678b8e + sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3" url: "https://pub.dev" source: hosted - version: "1.10.0" + version: "1.9.1" mime: dependency: transitive description: @@ -728,6 +728,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.27.7" + scgateway_flutter_plugin: + dependency: "direct main" + description: + name: scgateway_flutter_plugin + sha256: c52831292d73b7004af314f7e34ea4c510110da3e7d1cc274a745b3524e6a724 + url: "https://pub.dev" + source: hosted + version: "2.3.1" share_plus: dependency: transitive description: @@ -841,18 +849,18 @@ packages: dependency: transitive description: name: stack_trace - sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b" + sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5 url: "https://pub.dev" source: hosted - version: "1.11.1" + version: "1.11.0" stream_channel: dependency: transitive description: name: stream_channel - sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7 + sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8" url: "https://pub.dev" source: hosted - version: "2.1.2" + version: "2.1.1" string_scanner: dependency: transitive description: @@ -881,10 +889,10 @@ packages: dependency: transitive description: name: test_api - sha256: "5c2f730018264d276c20e4f1503fd1308dfbbae39ec8ee63c5236311ac06954b" + sha256: "75760ffd7786fffdfb9597c35c5b27eaeec82be8edfb6d71d32651128ed7aab8" url: "https://pub.dev" source: hosted - version: "0.6.1" + version: "0.6.0" typed_data: dependency: transitive description: @@ -913,10 +921,10 @@ packages: dependency: transitive description: name: url_launcher_web - sha256: fff0932192afeedf63cdd50ecbb1bc825d31aed259f02bb8dba0f3b729a5e88b + sha256: "7fd2f55fe86cea2897b963e864dc01a7eb0719ecc65fcef4c1cc3d686d718bb2" url: "https://pub.dev" source: hosted - version: "2.2.3" + version: "2.2.0" url_launcher_windows: dependency: transitive description: @@ -1058,10 +1066,10 @@ packages: dependency: transitive description: name: web - sha256: afe077240a270dcfd2aafe77602b4113645af95d0ad31128cc02bce5ac5d5152 + sha256: dc8ccd225a2005c1be616fe02951e2e342092edf968cf0844220383757ef8f10 url: "https://pub.dev" source: hosted - version: "0.3.0" + version: "0.1.4-beta" win32: dependency: transitive description: @@ -1087,5 +1095,5 @@ packages: source: hosted version: "6.3.0" sdks: - dart: ">=3.2.0 <4.0.0" - flutter: ">=3.16.0" + dart: ">=3.1.0 <4.0.0" + flutter: ">=3.13.0" diff --git a/pubspec.yaml b/pubspec.yaml index 8dd0737..1f9325b 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -39,6 +39,8 @@ dependencies: firebase_core: dio: ^5.1.2 expansion_tile_group: ^1.2.4 + scgateway_flutter_plugin: ^2.3.1 + async: ^2.4.1 dev_dependencies: flutter_test: @@ -63,4 +65,4 @@ flutter: - family: hiragino fonts: - - asset: assets/fonts/hiragino/HiraginoInterface.ttc + - asset: assets/fonts/hiragino/HiraginoInterface.ttc