From a8af1a13d72c60077c909bf209c9d84d3cc40c69 Mon Sep 17 00:00:00 2001 From: Ravi Gulhane Date: Wed, 4 Nov 2026 13:15:24 +0530 Subject: [PATCH 1/2] Changes --- app/Helpers/TgicsHelper.php | 87 +++++++++++ app/Http/Controllers/FormController.php | 47 ++++++ ...e937-cfb5-4679-989a-c3fea892568f.blade.php | 146 +++++++++++++++++- routes/web.php | 1 + 4 files changed, 276 insertions(+), 5 deletions(-) diff --git a/app/Helpers/TgicsHelper.php b/app/Helpers/TgicsHelper.php index b5a7846f..78fb0be0 100644 --- a/app/Helpers/TgicsHelper.php +++ b/app/Helpers/TgicsHelper.php @@ -2,6 +2,8 @@ namespace App\Helpers; +use App\Http\Requests\LambdaRequest; +use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Http; use Illuminate\Support\Facades\Log; @@ -58,4 +60,89 @@ class TgicsHelper return ['counts' => array_fill_keys($ids, 0), 'total' => 0]; } } + + /** + * Resolve a Rapport contact access token for a domain (e.g. lifemankind). + */ + public static function resolveContactAccessToken(string $domain): string + { + $domain = trim($domain); + if ($domain === '') { + return ''; + } + + $tokenRows = DB::table('users') + ->select('access_token') + ->where('domain', $domain) + ->where('permissions', 'like', '%contact_create%') + ->orderBy('updated_at', 'desc') + ->skip(0) + ->take(1) + ->get(); + + if ($tokenRows->isEmpty() || empty($tokenRows[0]->access_token)) { + return ''; + } + + return (string) $tokenRows[0]->access_token; + } + + public static function isWhatsappValidatedFlag($value): bool + { + if ($value === true || $value === 1 || $value === '1') { + return true; + } + return strtolower(trim((string) $value)) === 'yes'; + } + + /** + * Map contact_id => whether WhatsApp is validated for TGICS. + * + * @param array $contactIds + * @return array + */ + public static function getWhatsappValidationStatus(array $contactIds, string $domain = 'lifemankind'): array + { + $ids = array_values(array_unique(array_filter(array_map(static function ($id) { + return trim((string) $id); + }, $contactIds)))); + + if (count($ids) === 0) { + return []; + } + + $accessToken = self::resolveContactAccessToken($domain); + if ($accessToken === '') { + Log::warning('TGICS WhatsApp validation: no contact access token for domain '.$domain); + return array_fill_keys($ids, false); + } + + $status = array_fill_keys($ids, false); + foreach ($ids as $id) { + try { + $resp = LambdaRequest::getrequest('contact', 'contact/get_one', ['id' => $id], $accessToken); + $item = $resp->data->item ?? null; + if ($item && self::isWhatsappValidatedFlag($item->tgics_whatsapp_validated ?? '')) { + $status[$id] = true; + } + } catch (\Throwable $e) { + Log::warning('TGICS WhatsApp validation lookup failed for '.$id.': '.$e->getMessage()); + } + } + + return $status; + } + + /** + * Single-contact validation check for poll endpoint. + */ + public static function isContactWhatsappValidated(string $contactId, string $domain = 'lifemankind'): bool + { + $contactId = trim($contactId); + if ($contactId === '') { + return false; + } + $map = self::getWhatsappValidationStatus([$contactId], $domain); + return !empty($map[$contactId]); + } } diff --git a/app/Http/Controllers/FormController.php b/app/Http/Controllers/FormController.php index f2a530e7..e048d53a 100644 --- a/app/Http/Controllers/FormController.php +++ b/app/Http/Controllers/FormController.php @@ -1050,6 +1050,7 @@ class FormController extends Controller // Create contact on new enrolments; update linked contact on edits if ($currentSubmissionId === '') { + $contactdata['tgics_whatsapp_validated'] = 'No'; $cont = LambdaRequest::postrequest('contact', 'contact/create', $contactdata, $accessToken); if (!isset($cont->status) || $cont->status !== 'success' || empty($cont->data->item->id)) { return response()->json([ @@ -1061,6 +1062,21 @@ class FormController extends Controller $post['tgics_contact_id'] = $cont->data->item->id; } elseif ($linkedContactId !== '') { $contactdata['id'] = $linkedContactId; + $existingContact = LambdaRequest::getrequest('contact', 'contact/get_one', ['id' => $linkedContactId], $accessToken); + $existingItem = $existingContact->data->item ?? null; + $existingPhone = ''; + if ($existingItem && !empty($existingItem->phone)) { + $existingPhone = preg_replace('/\D+/', '', (string) $existingItem->phone); + if (strlen($existingPhone) > 10) { + $existingPhone = substr($existingPhone, -10); + } + } + if ($existingPhone !== '' && $existingPhone !== $whatsapp) { + $contactdata['tgics_whatsapp_validated'] = 'No'; + } elseif ($existingItem && isset($existingItem->tgics_whatsapp_validated)) { + $contactdata['tgics_whatsapp_validated'] = $existingItem->tgics_whatsapp_validated; + } + $cont = LambdaRequest::postrequest('contact', 'contact/update', $contactdata, $accessToken); if (!isset($cont->status) || $cont->status !== 'success') { return response()->json([ @@ -13513,4 +13529,35 @@ class FormController extends Controller return $labels; } + /** + * Poll endpoint: TGICS WhatsApp validation status for a contact. + */ + public function tgicsWhatsappStatus(Request $request) + { + $contactId = trim((string) $request->input('contact_id', '')); + $partition = trim((string) $request->input('partition', 'rapport-lifemankind')); + $domain = 'lifemankind'; + if (strpos($partition, '-') !== false) { + $parts = explode('-', $partition, 2); + $domain = $parts[1] ?? $domain; + } + + if ($contactId === '') { + return response()->json([ + 'status' => 'error', + 'message' => 'contact_id is required.', + ], 400); + } + + $validated = \App\Helpers\TgicsHelper::isContactWhatsappValidated($contactId, $domain); + + return response()->json([ + 'status' => 'success', + 'data' => [ + 'contact_id' => $contactId, + 'validated' => $validated, + ], + ]); + } + } \ No newline at end of file diff --git a/resources/views/form/rapport-lifemankind/1792561624-4466e937-cfb5-4679-989a-c3fea892568f.blade.php b/resources/views/form/rapport-lifemankind/1792561624-4466e937-cfb5-4679-989a-c3fea892568f.blade.php index b746ac2b..47d90dec 100644 --- a/resources/views/form/rapport-lifemankind/1792561624-4466e937-cfb5-4679-989a-c3fea892568f.blade.php +++ b/resources/views/form/rapport-lifemankind/1792561624-4466e937-cfb5-4679-989a-c3fea892568f.blade.php @@ -62,6 +62,10 @@ $tgicsSurveyData = \App\Helpers\TgicsHelper::getSurveyCounts($tgicsContactIds); $tgicsSurveyCounts = $tgicsSurveyData['counts'] ?? []; $totalSurveysDone = (int) ($tgicsSurveyData['total'] ?? 0); + $tgicsWhatsappValidated = \App\Helpers\TgicsHelper::getWhatsappValidationStatus( + $tgicsContactIds, + 'lifemankind' + ); $tgicsCommonUserId = trim((string) ($form->user_id ?? '')); $tgicsCommonLink = $tgicsCommonUserId !== '' @@ -135,23 +139,41 @@ $surveysDone = $tgicsContactId !== '' ? (int) ($tgicsSurveyCounts[$tgicsContactId] ?? 0) : 0; + $whatsappValidated = $tgicsContactId !== '' + && !empty($tgicsWhatsappValidated[$tgicsContactId]); $whatsappText = "Dear Doctor" . ($doctorName !== '' ? ' ' . $doctorName : '') . ",\nThank you for participating in TGICS (The Great Indian Cough Study).\nPlease open the link and enter your WhatsApp mobile number to continue:\n" . $doctorLink; $whatsappLink = ($whatsappDigits !== '' && $doctorLink !== '') ? 'https://api.whatsapp.com/send?phone=' . $whatsappDigits . '&text=' . rawurlencode($whatsappText) : ''; + $validateToken = $tgicsContactId !== '' + ? 'CREST_VERIFY_TGICS_' . $tgicsContactId + : ''; + $validateWaUrl = $validateToken !== '' + ? 'https://wa.me/918142061298?text=' . rawurlencode($validateToken) + : ''; @endphp @if ($isApproved) - @if ($whatsappLink !== '') + @if ($doctorLink === '') + Link unavailable + @elseif ($whatsappDigits === '') + No WhatsApp number + @elseif ($whatsappValidated && $whatsappLink !== '') - Send WhatsApp + Send - @elseif ($doctorLink === '') - Link unavailable + @elseif ($validateWaUrl !== '') + @else - No WhatsApp number + Validation unavailable @endif @else + + + + + + + @include('layouts.shared/footer-script') + @@ -825,6 +832,40 @@ } } + function hideTgicsValidateModal() { + stopTgicsWaPoll(); + var $modal = $('#tgics-validate-wa-modal'); + if ($.fn.modal && typeof $modal.modal === 'function') { + $modal.modal('hide'); + } else if (window.bootstrap && bootstrap.Modal) { + var inst = bootstrap.Modal.getInstance($modal[0]); + if (inst) { + inst.hide(); + } + } + $modal.removeClass('show').css('display', 'none').attr('aria-hidden', 'true'); + $('.tgics-validate-backdrop').remove(); + $('body').removeClass('modal-open').css('overflow', ''); + } + + function showTgicsValidateModal() { + var $modal = $('#tgics-validate-wa-modal'); + if ($.fn.modal && typeof $modal.modal === 'function') { + $modal.modal('show'); + return; + } + if (window.bootstrap && bootstrap.Modal) { + bootstrap.Modal.getOrCreateInstance($modal[0]).show(); + return; + } + // Manual fallback when Bootstrap modal JS is unavailable + $modal.addClass('show').css('display', 'block').attr('aria-hidden', 'false'); + if (!$('.tgics-validate-backdrop').length) { + $('body').append(''); + } + $('body').addClass('modal-open'); + } + function startTgicsWaPoll(contactId) { stopTgicsWaPoll(); tgicsWaPollStartedAt = Date.now(); @@ -862,40 +903,57 @@ }, 3000); } - $(document).on('click', '.tgics-validate-wa-btn', function() { + $(document).on('click', '.tgics-validate-wa-btn', function(e) { + e.preventDefault(); + e.stopPropagation(); var contactId = $(this).attr('data-contact-id') || ''; var validateUrl = $(this).attr('data-validate-url') || ''; var doctorName = $(this).attr('data-doctor-name') || 'Doctor'; if (!contactId || !validateUrl) { + Swal.fire({ + icon: 'error', + title: 'Validation unavailable', + text: 'Missing doctor contact link. Please re-enrol or contact support.' + }); return; } $('#tgics-validate-wa-doctor').text(doctorName); $('#tgics-validate-wa-open').attr('href', validateUrl); $('#tgics-validate-wa-qr').empty(); - if (typeof QRCode !== 'undefined') { - new QRCode(document.getElementById('tgics-validate-wa-qr'), { - text: validateUrl, - width: 200, - height: 200 - }); - } else { - $('#tgics-validate-wa-qr').html('

Unable to render QR. Use Open link instead.

'); + try { + if (typeof QRCode !== 'undefined') { + new QRCode(document.getElementById('tgics-validate-wa-qr'), { + text: validateUrl, + width: 200, + height: 200 + }); + } else { + $('#tgics-validate-wa-qr').html( + '

QR library unavailable. Use the button below.

' + ); + } + } catch (qrErr) { + console.error(qrErr); + $('#tgics-validate-wa-qr').html( + '

Unable to render QR. Use the button below.

' + ); } - var $modal = $('#tgics-validate-wa-modal'); - if (typeof bootstrap !== 'undefined' && bootstrap.Modal) { - bootstrap.Modal.getOrCreateInstance($modal[0]).show(); - } else if ($modal.modal) { - $modal.modal('show'); - } else { - $modal.show(); - } + showTgicsValidateModal(); startTgicsWaPoll(contactId); }); + $(document).on('click', '#tgics-validate-wa-modal [data-bs-dismiss="modal"], #tgics-validate-wa-modal .btn-close, #tgics-validate-wa-modal .btn-secondary', function() { + hideTgicsValidateModal(); + }); + $(document).on('click', '.tgics-validate-backdrop', function() { + hideTgicsValidateModal(); + }); + $('#tgics-validate-wa-modal').on('hidden.bs.modal hide.bs.modal', function() { stopTgicsWaPoll(); + $('.tgics-validate-backdrop').remove(); }); $('#execution-form').on('submit', function(event) { @@ -944,28 +1002,27 @@ today = yyyy + '-' + mm + '-' + dd; var recordDateField = document.getElementById('field-plan_date'); - recordDateField.setAttribute('min', today); + if (recordDateField) { + recordDateField.setAttribute('min', today); + } var executionDateField = document.getElementById('execution-plan_date'); - //executionDateField.setAttribute('min', today); - - // $('.edit-btn').click(function() { - // var executionexeField = document.getElementById('execution-record_date'); - // executionexeField.setAttribute('min', executionDateField.value); - // }); $('.edit-btn').click(function() { var executionexeField = document.getElementById('execution-execution_date'); - executionexeField.setAttribute('min', executionDateField.value); + if (executionexeField && executionDateField && executionDateField.value) { + executionexeField.setAttribute('min', executionDateField.value); + } }); - - - executionDateField.addEventListener('change', function() { - console.log('gg'); - var executionexeField = document.getElementById('execution-record_date'); - executionexeField.setAttribute('min', executionDateField.value); - }); + if (executionDateField) { + executionDateField.addEventListener('change', function() { + var executionexeField = document.getElementById('execution-record_date'); + if (executionexeField) { + executionexeField.setAttribute('min', executionDateField.value); + } + }); + } });