verificacion.dart 40 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923
  1. import 'dart:convert';
  2. import 'dart:math';
  3. import 'package:fluttertoast/fluttertoast.dart';
  4. import 'package:google_fonts/google_fonts.dart';
  5. import 'package:http/http.dart' as http;
  6. import 'package:flutter/material.dart';
  7. import 'package:localstore/localstore.dart';
  8. import 'package:pin_code_fields/pin_code_fields.dart';
  9. import '../widgets/encabezado_pais.dart';
  10. class VerificacionPage extends StatefulWidget {
  11. final String correo;
  12. final String numTel;
  13. final String pais;
  14. final String verificacion;
  15. final String idUsuario;
  16. const VerificacionPage({
  17. Key? key,
  18. required this.correo,
  19. required this.numTel,
  20. required this.pais,
  21. required this.verificacion,
  22. required this.idUsuario,
  23. }) : super(key: key);
  24. @override
  25. State<VerificacionPage> createState() => _VerificacionPageState();
  26. }
  27. class _VerificacionPageState extends State<VerificacionPage> {
  28. late String _phone;
  29. late String _email;
  30. late String _pais;
  31. late String _keyPhone;
  32. late String _keyEmail;
  33. final _url = "smart.solerpalau.mx";
  34. final db = Localstore.instance;
  35. bool _exedioPhone = false;
  36. bool _exedioEmail = false;
  37. bool _validoEmail = false;
  38. bool _validoPhone = false;
  39. bool _errorPhone = false;
  40. bool _errorEmail = false;
  41. bool _isLoading = true;
  42. int _intentosPhone = 1;
  43. int _intentosEmail = 1;
  44. final String _code = "";
  45. TextEditingController _codigoController = TextEditingController();
  46. TextEditingController _codigoTelController = TextEditingController();
  47. @override
  48. void initState() {
  49. super.initState();
  50. _phone = widget.numTel;
  51. _email = widget.correo;
  52. _pais = widget.pais;
  53. _keyPhone = _generateKey();
  54. _keyEmail = _generateKey();
  55. _enviosprimero(widget.verificacion);
  56. }
  57. String _generateKey(){
  58. final rand = Random();
  59. String num = rand.nextInt(999999).toString();
  60. for(int i = num.length; i < 6; i++) {
  61. num = "0$num";
  62. }
  63. return num;
  64. }
  65. Future<void> _enviosprimero(String verificacion) async{
  66. if(verificacion == "1"){
  67. final correoResp = await _sendCorreo(_email, _keyEmail);
  68. final movilResp = await _sendPhone(_phone, _keyPhone);
  69. _errorEmail = !correoResp;
  70. _errorPhone = !movilResp;
  71. }else if(verificacion == "2"){
  72. final movilResp = await _sendPhone(_phone, _keyPhone);
  73. _errorEmail = false;
  74. _validoEmail = true;
  75. _errorPhone = !movilResp;
  76. }else if(verificacion == "3"){
  77. final correoResp = await _sendCorreo(_email, _keyEmail);
  78. _errorEmail = !correoResp;
  79. _validoPhone = true;
  80. _errorPhone = false;
  81. }else{
  82. _errorEmail = false;
  83. _errorPhone = false;
  84. _validoEmail = true;
  85. _validoPhone = true;
  86. }
  87. /*print("===EMAIL: $_keyEmail===");
  88. print("===PHONE: $_keyPhone===");*/
  89. setState(() => _isLoading = false);
  90. }
  91. Future<bool> _sendCorreo(String correo, String otp) async{
  92. final url = Uri.https(_url, "PR/api/v1/matrizMemoriasCalculo/sendOTPemail");
  93. final res = await http.post(url,
  94. body: {
  95. "CORREO": correo,
  96. "OTP" : otp,
  97. "DATE" : _orderDate("${DateTime.now()}".substring(0, 16)),
  98. "UNTIL" : "el ${_orderDate("${DateTime.now().add(const Duration(minutes: 5))}".substring(0, 16))}",
  99. "YEAR" : "${DateTime.now().year}"
  100. }
  101. );
  102. final decoded = jsonDecode(res.body);
  103. return decoded['response'];
  104. }
  105. Future<bool> _sendPhone(String movil, String otp) async{
  106. final url = Uri.https("jlbn.plataforma-educativa.com.mx", "sms/");
  107. final res = await http.post(url,
  108. body: {
  109. "MOVIL" : movil,
  110. "OTP" : otp,
  111. "DATE" : _orderDate('${DateTime.now()}'.substring(0, 16)).toUpperCase(),
  112. "UNTIL" : _orderDate("${DateTime.now().add(const Duration(minutes: 5))}".substring(0, 16)),
  113. "YEAR" : "${DateTime.now().year}",
  114. "PAIS" : _pais
  115. }
  116. );
  117. final dec = jsonDecode(res.body);
  118. return !dec['error'];
  119. }
  120. String _orderDate(String dateTime){
  121. final months = {
  122. "01": "enero", "02": "febrero", "03": "marzo", "04": "abril", "05": "mayo", "06": "junio", "07": "julio",
  123. "08": "agosto", "09": "septiembre", "10": "octubre", "11": "noviembre", "12": "diciembre"
  124. };
  125. final dateTimeArr = dateTime.split(" ");
  126. final date = dateTimeArr.first;
  127. final dateArr = date.split("-");
  128. return "${dateArr[2]} de ${months[dateArr[1]]} del ${dateArr[0]} a las ${dateTimeArr.last} hrs";
  129. }
  130. @override
  131. Widget build(BuildContext context) {
  132. final _screenSize = MediaQuery.of(context).size;
  133. return Scaffold(
  134. body: _isLoading ? const Center(
  135. child: CircularProgressIndicator(),
  136. ) : _errorPhone || _errorEmail ? AlertDialog(
  137. title: Text(
  138. "¡ERROR!",
  139. style: GoogleFonts.robotoSlab(
  140. fontSize: 24.0,
  141. fontWeight: FontWeight.bold,
  142. color: const Color.fromRGBO(180, 4, 4, 1)
  143. ),
  144. ),
  145. content: Column(
  146. mainAxisSize: MainAxisSize.min,
  147. mainAxisAlignment: MainAxisAlignment.center,
  148. crossAxisAlignment: CrossAxisAlignment.center,
  149. children: [
  150. Image.asset(
  151. "error.png",
  152. width: 72.0,
  153. ),
  154. const SizedBox(height: 8.0),
  155. Text(
  156. "Se presentaron los siguientes errores al tratar de comunicarnos con usted:",
  157. style: GoogleFonts.roboto(),
  158. ),
  159. if(_errorEmail)
  160. const SizedBox(height: 8.0),
  161. if(_errorEmail)
  162. Text(
  163. "-Error al enviar el correo electrónico",
  164. style: GoogleFonts.roboto(
  165. fontWeight: FontWeight.bold,
  166. fontStyle: FontStyle.italic,
  167. ),
  168. ),
  169. if(_errorPhone)
  170. const SizedBox(height: 8.0),
  171. if(_errorPhone)
  172. Text(
  173. "-Error al enviar el SMS",
  174. style: GoogleFonts.roboto(
  175. fontWeight: FontWeight.bold,
  176. fontStyle: FontStyle.italic,
  177. ),
  178. ),
  179. const SizedBox(height: 8.0),
  180. Text(
  181. "Por favor contacte al departamento de TI de S&P México si alguno de los errores persiste.",
  182. style: GoogleFonts.roboto(),
  183. ),
  184. ],
  185. ),
  186. actions: [
  187. TextButton(
  188. child: const Text("Cerrar"),
  189. onPressed: () => Navigator.pop(context),
  190. )
  191. ],
  192. ) : SafeArea(
  193. child: SingleChildScrollView(
  194. child: Column(
  195. mainAxisAlignment: MainAxisAlignment.start,
  196. crossAxisAlignment: CrossAxisAlignment.center,
  197. mainAxisSize: MainAxisSize.max,
  198. children: [
  199. Container(
  200. margin: const EdgeInsets.fromLTRB(32.0, 0.0, 16.0, 0.0),
  201. padding: const EdgeInsets.fromLTRB(0.0, 8.0, 0.0, 0.0),
  202. width: double.infinity,
  203. child: Row(
  204. children: [
  205. Expanded(
  206. child: Text(
  207. "Portal de memorias de cálculo",
  208. style: GoogleFonts.roboto(
  209. fontSize: 16.0,
  210. color: Colors.black54,
  211. fontWeight: FontWeight.bold,
  212. fontStyle: FontStyle.italic,
  213. ),
  214. ),
  215. ),
  216. const SizedBox(width: 8.0),
  217. IconButton(
  218. icon: const Icon(Icons.logout, color: Color(0xFFB40404)),
  219. onPressed: () => Navigator.pop(context, 'logout'),
  220. ),
  221. ],
  222. ),
  223. ),
  224. const SizedBox(height: 8.0),
  225. EncabezadoPais(
  226. paisCode: _code,
  227. paisName: _pais,
  228. ),
  229. const SizedBox(
  230. height: 32.0,
  231. ),
  232. Image.asset(
  233. "assets/matriz.png",
  234. width: 88.0,
  235. fit: BoxFit.cover,
  236. ),
  237. const SizedBox(
  238. height: 16.0,
  239. ),
  240. Container(
  241. width: double.infinity,
  242. padding: const EdgeInsets.symmetric(horizontal: 32.0),
  243. child: const Text(
  244. "PORTAL DE MEMORIAS DE CÁLCULO",
  245. textAlign: TextAlign.center,
  246. style: TextStyle(
  247. fontFamily: "Helvetica Neue Black Cond",
  248. fontSize: 28.0,
  249. ),
  250. ),
  251. ),
  252. const SizedBox(
  253. height: 8.0,
  254. ),
  255. Container(
  256. padding: const EdgeInsets.symmetric(horizontal: 32.0),
  257. width: double.infinity,
  258. child: const Text(
  259. "Antes de continuar vamos a verificar tu correo y número de teléfono.",
  260. textAlign: TextAlign.center,
  261. style: TextStyle(
  262. fontFamily: "Helvetica Neue Light",
  263. fontSize: 22.0,
  264. fontWeight: FontWeight.w600,
  265. color: Color.fromRGBO(104, 104, 104, 1)
  266. ),
  267. ),
  268. ),
  269. const SizedBox(
  270. height: 32.0,
  271. ),
  272. if(widget.verificacion == "1" || widget.verificacion == "3")
  273. Container(
  274. width: double.infinity,
  275. margin: const EdgeInsets.symmetric(horizontal: 32.0),
  276. decoration: widget.verificacion == "1" ? const BoxDecoration(
  277. border: Border(
  278. bottom: BorderSide(
  279. color: Colors.black12,
  280. ),
  281. ),
  282. ) : null,
  283. child: Column(
  284. mainAxisAlignment: MainAxisAlignment.center,
  285. crossAxisAlignment: CrossAxisAlignment.center,
  286. children: [
  287. Text(
  288. "Hemos enviado un código a tu correo electrónico. Por favor ingresalo debajo.",
  289. textAlign: TextAlign.center,
  290. style: GoogleFonts.roboto(
  291. color: Colors.grey,
  292. fontSize: 18.0,
  293. ),
  294. ),
  295. const SizedBox(height: 16.0),
  296. TextButton(
  297. child: Text(
  298. "Mi correo electrónico no es $_email, quiero cambiarlo.",
  299. style: GoogleFonts.roboto(
  300. fontSize: 12.0,
  301. ),
  302. ),
  303. onPressed: () async{
  304. final newEmailController = TextEditingController();
  305. final shouldRefresh = await showDialog(
  306. context: context,
  307. barrierDismissible: false,
  308. builder: (context) => AlertDialog(
  309. title: const Text("Cambiar correo electrónico."),
  310. content: Column(
  311. mainAxisSize: MainAxisSize.min,
  312. children: [
  313. Text(
  314. "Ingresa el nuevo correo electrónico:",
  315. style: GoogleFonts.roboto(),
  316. ),
  317. TextField(
  318. controller: newEmailController,
  319. decoration: InputDecoration(
  320. hintText: "ejemplo@ejemplo.com",
  321. hintStyle: GoogleFonts.roboto(
  322. fontStyle: FontStyle.italic,
  323. color: Colors.black54,
  324. ),
  325. ),
  326. ),
  327. ],
  328. ),
  329. actions: [
  330. TextButton(
  331. child: Text(
  332. "Cancelar",
  333. style: GoogleFonts.roboto(),
  334. ),
  335. onPressed: () => Navigator.pop(context, false),
  336. ),
  337. TextButton(
  338. child: Text(
  339. "Aceptar",
  340. style: GoogleFonts.roboto(),
  341. ),
  342. onPressed: (){
  343. const pattern = r'^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$';
  344. final regExp = RegExp(pattern);
  345. if(!regExp.hasMatch(newEmailController.text)){
  346. Fluttertoast.showToast(
  347. msg: "El correo no tiene un formato válido.",
  348. toastLength: Toast.LENGTH_SHORT,
  349. timeInSecForIosWeb: 4,
  350. gravity: ToastGravity.CENTER,
  351. webBgColor: "linear-gradient(to right, #b40404, #ff0000)",
  352. );
  353. }else{
  354. Navigator.pop(context, true);
  355. }
  356. },
  357. )
  358. ],
  359. )
  360. );
  361. if(shouldRefresh && newEmailController.text != _email){
  362. final url = Uri.https(_url, "PR/api/v1/matrizMemoriasCalculo/actualizarCuenta");
  363. final res = await http.post(url,
  364. body: {
  365. "IDUSUARIO" : widget.idUsuario,
  366. "MOVIL" : "",
  367. "CORREO" : newEmailController.text
  368. },
  369. );
  370. final decoded = jsonDecode(res.body);
  371. if(decoded['response']){
  372. setState(() {
  373. _email = newEmailController.text;
  374. _exedioEmail = false;
  375. _intentosEmail = 1;
  376. _isLoading = true;
  377. _keyEmail = _generateKey();
  378. });
  379. await _sendCorreo(_email, _keyEmail);
  380. setState((){
  381. _codigoController = TextEditingController();
  382. _codigoTelController = TextEditingController();
  383. _isLoading = false;
  384. });
  385. }else{
  386. Fluttertoast.showToast(
  387. msg: "No se pudo enviar el correo.",
  388. toastLength: Toast.LENGTH_SHORT,
  389. timeInSecForIosWeb: 4,
  390. gravity: ToastGravity.CENTER,
  391. webBgColor: "linear-gradient(to right, #b40404, #ff0000)",
  392. );
  393. }
  394. }else{
  395. Fluttertoast.showToast(
  396. msg: "Ambos correos son iguales, por favor revisa tu bandeja de entrada.",
  397. toastLength: Toast.LENGTH_SHORT,
  398. timeInSecForIosWeb: 4,
  399. gravity: ToastGravity.CENTER,
  400. webBgColor: "linear-gradient(to right, #b40404, #ff0000)",
  401. );
  402. }
  403. },
  404. ),
  405. const SizedBox(height: 16.0),
  406. Text(
  407. "Código:",
  408. textAlign: TextAlign.center,
  409. style: GoogleFonts.roboto(
  410. fontSize: 18.0,
  411. ),
  412. ),
  413. const SizedBox(height: 16.0),
  414. SizedBox(
  415. width: 256.0,
  416. child: _exedioEmail ? ElevatedButton(
  417. child: Text(
  418. "Generar nuevo código",
  419. style: GoogleFonts.roboto(),
  420. ),
  421. onPressed: () async{
  422. final newPin = _generateKey();
  423. setState(() => _keyEmail = newPin);
  424. await _sendCorreo(_email, newPin);
  425. setState(() {
  426. _exedioEmail = false;
  427. _intentosEmail = 1;
  428. _codigoController = TextEditingController();
  429. });
  430. },
  431. ) : AnimatedCrossFade(
  432. firstChild: Row(
  433. children: [
  434. Expanded(
  435. child: Text(
  436. _keyEmail,
  437. textAlign: TextAlign.center,
  438. style: GoogleFonts.roboto(
  439. fontSize: 32.0,
  440. fontWeight: FontWeight.bold,
  441. color: Colors.green,
  442. letterSpacing: 16.0
  443. ),
  444. ),
  445. ),
  446. const SizedBox(width: 8.0),
  447. const SizedBox(
  448. width: 32.0,
  449. height: 32.0,
  450. child: Icon(
  451. Icons.check_circle,
  452. color: Colors.green,
  453. ),
  454. )
  455. ],
  456. ),
  457. secondChild: Row(
  458. children: [
  459. const SizedBox(height: 12.0),
  460. Expanded(child: PinCodeTextField(
  461. appContext: context,
  462. length: 6,
  463. obscureText: false,
  464. animationType: AnimationType.fade,
  465. pinTheme: PinTheme(
  466. shape: PinCodeFieldShape.underline,
  467. fieldHeight: 32.0,
  468. fieldWidth: 32.0,
  469. activeFillColor: const Color(0xFFB40404),
  470. activeColor: const Color(0xFFB40404),
  471. selectedColor: const Color(0xFFFF0000),
  472. selectedFillColor: Colors.black26,
  473. inactiveColor: Colors.transparent,
  474. disabledColor: Colors.transparent,
  475. inactiveFillColor: Colors.black12,
  476. ),
  477. animationDuration: const Duration(milliseconds: 250),
  478. textStyle: GoogleFonts.roboto(
  479. color: Colors.white,
  480. fontWeight: FontWeight.bold,
  481. ),
  482. enableActiveFill: true,
  483. controller: _codigoController,
  484. enabled: !_validoEmail,
  485. onCompleted: (value) async{
  486. if(_codigoController.text != _keyEmail && _intentosEmail < 5){
  487. Fluttertoast.showToast(
  488. msg: "El código que ingresó es incorrecto. Intento $_intentosEmail de 5.",
  489. toastLength: Toast.LENGTH_SHORT,
  490. timeInSecForIosWeb: 4,
  491. gravity: ToastGravity.CENTER,
  492. webBgColor: "linear-gradient(to right, #b40404, #ff0000)",
  493. );
  494. _codigoController.clear();
  495. setState(() => _intentosEmail++ );
  496. }else if(_codigoController.text == _keyEmail){
  497. setState(() => _validoEmail = true);
  498. final url = Uri.https(_url, "PR/api/v1/matrizMemoriasCalculo/verificarCuenta");
  499. final res = await http.post(url,
  500. body: {
  501. "IDUSUARIO" : widget.idUsuario,
  502. "VERIFICACION" : "correo"
  503. },
  504. );
  505. final decoded = jsonDecode(res.body);
  506. if(!decoded['response']){
  507. final items = await db.collection("login").get();
  508. final lastID = items?.keys.last;
  509. final info = items![lastID];
  510. info['verificacion'] = "2";
  511. db.collection('login').doc(lastID).set(info);
  512. Fluttertoast.showToast(
  513. msg: "No se pudo actualizar su verificación en el servidor.",
  514. toastLength: Toast.LENGTH_SHORT,
  515. timeInSecForIosWeb: 4,
  516. gravity: ToastGravity.CENTER,
  517. webBgColor: "linear-gradient(to right, #b40404, #ff0000)",
  518. );
  519. }
  520. }else{
  521. setState(() {
  522. _intentosEmail = 1;
  523. _exedioEmail = true;
  524. });
  525. }
  526. },
  527. onChanged: (val) => false,
  528. )),
  529. const SizedBox(height: 12.0),
  530. ],
  531. ),
  532. crossFadeState: _validoEmail ? CrossFadeState.showFirst : CrossFadeState.showSecond,
  533. duration: const Duration(milliseconds: 250),
  534. ),
  535. ),
  536. const SizedBox(height: 16.0),
  537. ],
  538. ),
  539. ),
  540. if(widget.verificacion == "1" || widget.verificacion == "2")
  541. const SizedBox(height: 32.0),
  542. if(widget.verificacion == "1" || widget.verificacion == "2")
  543. Container(
  544. width: double.infinity,
  545. margin: const EdgeInsets.symmetric(horizontal: 32.0),
  546. child: Column(
  547. mainAxisAlignment: MainAxisAlignment.center,
  548. crossAxisAlignment: CrossAxisAlignment.center,
  549. children: [
  550. Text(
  551. "Hemos enviado un código a tu número telefónico. Por favor ingresalo debajo.",
  552. textAlign: TextAlign.center,
  553. style: GoogleFonts.roboto(
  554. color: Colors.grey,
  555. fontSize: 18.0,
  556. ),
  557. ),
  558. const SizedBox(height: 16.0),
  559. TextButton(
  560. child: Text(
  561. "Mi número telefónico no es $_phone, quiero cambiarlo.",
  562. style: GoogleFonts.roboto(
  563. fontSize: 12.0,
  564. ),
  565. ),
  566. onPressed: () async{
  567. final newPhoneController = TextEditingController();
  568. final shouldRefresh = await showDialog(
  569. context: context,
  570. barrierDismissible: false,
  571. builder: (context) => AlertDialog(
  572. title: const Text("Cambiar número telefónico."),
  573. content: Column(
  574. mainAxisSize: MainAxisSize.min,
  575. children: [
  576. Text(
  577. "Ingresa el nuevo número de teléfono:",
  578. style: GoogleFonts.roboto(),
  579. ),
  580. TextField(
  581. controller: newPhoneController,
  582. decoration: InputDecoration(
  583. hintText: "7771234567",
  584. hintStyle: GoogleFonts.roboto(
  585. fontStyle: FontStyle.italic,
  586. color: Colors.black54,
  587. ),
  588. ),
  589. )
  590. ],
  591. ),
  592. actions: [
  593. TextButton(
  594. child: Text(
  595. "Cancelar",
  596. style: GoogleFonts.roboto(),
  597. ),
  598. onPressed: () => Navigator.pop(context, false),
  599. ),
  600. TextButton(
  601. child: Text(
  602. "Aceptar",
  603. style: GoogleFonts.roboto(),
  604. ),
  605. onPressed: (){
  606. Navigator.pop(context, true);
  607. },
  608. ),
  609. ],
  610. )
  611. );
  612. if(shouldRefresh && newPhoneController.text != _phone){
  613. final url = Uri.https(_url, "PR/api/v1/matrizMemoriasCalculo/actualizarCuenta");
  614. final res = await http.post(url,
  615. body: {
  616. "IDUSUARIO" : widget.idUsuario,
  617. "MOVIL" : newPhoneController.text,
  618. "CORREO" : "",
  619. },
  620. );
  621. final decoded = jsonDecode(res.body);
  622. if(decoded['response']){
  623. setState(() {
  624. _phone = newPhoneController.text;
  625. _exedioPhone = false;
  626. _intentosPhone = 1;
  627. _isLoading = true;
  628. _keyPhone = _generateKey();
  629. });
  630. await _sendPhone(_phone, _keyPhone);
  631. setState((){
  632. _codigoController = TextEditingController();
  633. _codigoTelController = TextEditingController();
  634. _isLoading = false;
  635. });
  636. }else{
  637. Fluttertoast.showToast(
  638. msg: "No se pudo enviar el SMS.",
  639. toastLength: Toast.LENGTH_SHORT,
  640. timeInSecForIosWeb: 4,
  641. gravity: ToastGravity.CENTER,
  642. webBgColor: "linear-gradient(to right, #b40404, #ff0000)",
  643. );
  644. }
  645. }else{
  646. Fluttertoast.showToast(
  647. msg: "Ambos teléfonos son iguales, por favor revisa tus mensajes nuevos.",
  648. toastLength: Toast.LENGTH_SHORT,
  649. timeInSecForIosWeb: 4,
  650. gravity: ToastGravity.CENTER,
  651. webBgColor: "linear-gradient(to right, #b40404, #ff0000)",
  652. );
  653. }
  654. },
  655. ),
  656. const SizedBox(height: 16.0),
  657. Text(
  658. "Código:",
  659. textAlign: TextAlign.center,
  660. style: GoogleFonts.roboto(
  661. fontSize: 18.0,
  662. ),
  663. ),
  664. const SizedBox(height: 16.0),
  665. SizedBox(
  666. width: 256,
  667. child: _exedioPhone ? ElevatedButton(
  668. child: Text(
  669. "Generar nuevo código",
  670. style: GoogleFonts.roboto(),
  671. ),
  672. onPressed: () async{
  673. final newPin = _generateKey();
  674. setState(() => _keyPhone = newPin);
  675. await _sendPhone(_phone, newPin);
  676. setState((){
  677. _exedioPhone = false;
  678. _intentosPhone = 1;
  679. _codigoTelController = TextEditingController();
  680. });
  681. },
  682. ) : AnimatedCrossFade(
  683. firstChild: Row(
  684. children: [
  685. Expanded(
  686. child: Text(
  687. _keyPhone,
  688. textAlign: TextAlign.center,
  689. style: GoogleFonts.roboto(
  690. fontSize: 32.0,
  691. fontWeight: FontWeight.bold,
  692. color: Colors.green,
  693. letterSpacing: 16.0,
  694. ),
  695. ),
  696. ),
  697. const SizedBox(width: 8.0),
  698. const SizedBox(
  699. width: 32.0,
  700. height: 32.0,
  701. child: Icon(
  702. Icons.check_circle,
  703. color: Colors.green,
  704. ),
  705. )
  706. ],
  707. ),
  708. secondChild: Row(
  709. children: [
  710. const SizedBox(width: 12.0),
  711. Expanded(child: PinCodeTextField(
  712. appContext: context,
  713. length: 6,
  714. obscureText: false,
  715. animationType: AnimationType.fade,
  716. pinTheme: PinTheme(
  717. shape: PinCodeFieldShape.underline,
  718. fieldHeight: 32.0,
  719. fieldWidth: 32.0,
  720. activeFillColor: const Color(0xFFB40404),
  721. activeColor: const Color(0xFFB40404),
  722. selectedColor: const Color(0xFFFF0000),
  723. selectedFillColor: Colors.black26,
  724. inactiveColor: Colors.transparent,
  725. disabledColor: Colors.transparent,
  726. inactiveFillColor: Colors.black12,
  727. ),
  728. animationDuration: const Duration(milliseconds: 250),
  729. textStyle: GoogleFonts.roboto(
  730. color: Colors.white,
  731. fontWeight: FontWeight.bold,
  732. ),
  733. enableActiveFill: true,
  734. controller: _codigoTelController,
  735. onCompleted: (value) async{
  736. if(_codigoTelController.text != _keyPhone && _intentosPhone < 5){
  737. Fluttertoast.showToast(
  738. msg: "El código que ingresaste es incorrecto. Intento $_intentosPhone de 5.",
  739. toastLength: Toast.LENGTH_SHORT,
  740. timeInSecForIosWeb: 4,
  741. gravity: ToastGravity.CENTER,
  742. webBgColor: "linear-gradient(to right, #b40404, #ff0000)",
  743. );
  744. _codigoTelController.clear();
  745. setState(() {
  746. _intentosPhone++;
  747. });
  748. }else if(_codigoTelController.text == _keyPhone){
  749. setState(() {
  750. _validoPhone = true;
  751. });
  752. final url = Uri.https(_url, "PR/api/v1/matrizMemoriasCalculo/verificarCuenta");
  753. final res = await http.post(url,
  754. body: {
  755. "IDUSUARIO" : widget.idUsuario,
  756. "VERIFICACION" : "movil"
  757. },
  758. );
  759. final decoded = jsonDecode(res.body);
  760. if(!decoded['response']){
  761. final items = await db.collection("login").get();
  762. final lastID = items?.keys.last;
  763. final info = items![lastID];
  764. info['verificacion'] = "3";
  765. db.collection('login').doc(lastID).set(info);
  766. Fluttertoast.showToast(
  767. msg: "No se pudo actualizar su verificación en el servidor.",
  768. toastLength: Toast.LENGTH_SHORT,
  769. timeInSecForIosWeb: 4,
  770. gravity: ToastGravity.CENTER,
  771. webBgColor: "linear-gradient(to right, #b40404, #ff0000)",
  772. );
  773. }
  774. }else{
  775. setState(() {
  776. _intentosPhone = 1;
  777. _exedioPhone = true;
  778. });
  779. }
  780. },
  781. onChanged: (val) => false,
  782. )),
  783. const SizedBox(width: 12.0),
  784. ],
  785. ),
  786. crossFadeState: _validoPhone ? CrossFadeState.showFirst : CrossFadeState.showSecond,
  787. duration: const Duration(milliseconds: 250),
  788. ),
  789. ),
  790. const SizedBox(height: 16.0),
  791. ],
  792. ),
  793. ),
  794. const SizedBox(height: 32.0),
  795. Container(
  796. width: double.infinity,
  797. margin: const EdgeInsets.symmetric(horizontal: 32.0),
  798. child: Column(
  799. children: [
  800. MaterialButton(
  801. elevation: 4.0,
  802. padding: const EdgeInsets.symmetric(vertical: 8.0),
  803. minWidth: _screenSize.width-64.0,
  804. color: const Color(0xFFFF0000),
  805. child: Row(
  806. crossAxisAlignment: CrossAxisAlignment.center,
  807. mainAxisAlignment: MainAxisAlignment.center,
  808. children: const [
  809. Icon(
  810. Icons.arrow_back,
  811. color: Colors.white,
  812. size: 32.0,
  813. ),
  814. SizedBox(width: 8.0),
  815. Text(
  816. "Regresar",
  817. style: TextStyle(
  818. fontFamily: "Helvetica Neue Black Cond",
  819. fontSize: 28.0,
  820. color: Colors.white,
  821. ),
  822. ),
  823. ],
  824. ),
  825. onPressed: () => Navigator.pop(context),
  826. ),
  827. const SizedBox(height: 16.0),
  828. MaterialButton(
  829. elevation: 4.0,
  830. padding: const EdgeInsets.symmetric(vertical: 8.0),
  831. minWidth: _screenSize.width-64,
  832. color: const Color(0xFFFF0000),
  833. child: Row(
  834. crossAxisAlignment: CrossAxisAlignment.center,
  835. mainAxisAlignment: MainAxisAlignment.center,
  836. children: [
  837. Image.asset(
  838. "assets/continuar.png",
  839. width: 32.0,
  840. ),
  841. const SizedBox(width: 8.0),
  842. const Text(
  843. "Continuar",
  844. style: TextStyle(
  845. fontFamily: "Helvetica Neue Black Cond",
  846. fontSize: 28.0,
  847. color: Colors.white,
  848. ),
  849. ),
  850. ],
  851. ),
  852. disabledColor: Colors.grey,
  853. onPressed: _validoEmail && _validoPhone ? () async{
  854. final action = await Navigator.pushNamed(context, "indexMC");
  855. if(action == "logout"){
  856. final items = await db.collection('login').get();
  857. items!.forEach((key, value) {
  858. db.collection('login').doc(key).delete();
  859. });
  860. Navigator.pop(context);
  861. }
  862. } : null,
  863. ),
  864. ],
  865. ),
  866. ),
  867. const SizedBox(height: 32.0),
  868. ],
  869. ),
  870. ),
  871. ),
  872. );
  873. }
  874. }