Merge branch 'main' of http://192.168.1.200:3000/Stratawiz/Rapport-Laravel
Specific Folder FTP Upload / ftp-deploy (push) Successful in 30s
Details
Specific Folder FTP Upload / ftp-deploy (push) Successful in 30s
Details
This commit is contained in:
commit
a678cfdc55
|
|
@ -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<int, string> $contactIds
|
||||
* @return array<string, bool>
|
||||
*/
|
||||
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]);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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
|
||||
<tr>
|
||||
<td>
|
||||
@if ($isApproved)
|
||||
@if ($whatsappLink !== '')
|
||||
@if ($doctorLink === '')
|
||||
<span class="text-muted">Link unavailable</span>
|
||||
@elseif ($whatsappDigits === '')
|
||||
<span class="text-muted">No WhatsApp number</span>
|
||||
@elseif ($whatsappValidated && $whatsappLink !== '')
|
||||
<a href="{{ $whatsappLink }}" target="_blank" rel="noopener noreferrer"
|
||||
class="btn btn-xs btn-success">
|
||||
<i class="mdi mdi-whatsapp"></i> Send WhatsApp
|
||||
<i class="mdi mdi-whatsapp"></i> Send
|
||||
</a>
|
||||
@elseif ($doctorLink === '')
|
||||
<span class="text-muted">Link unavailable</span>
|
||||
@elseif ($validateWaUrl !== '')
|
||||
<button type="button"
|
||||
class="btn btn-xs btn-warning tgics-validate-wa-btn"
|
||||
data-contact-id="{{ $tgicsContactId }}"
|
||||
data-validate-url="{{ $validateWaUrl }}"
|
||||
data-doctor-name="{{ $doctorName }}">
|
||||
<i class="mdi mdi-qrcode"></i> Validate
|
||||
</button>
|
||||
@else
|
||||
<span class="text-muted">No WhatsApp number</span>
|
||||
<span class="text-muted">Validation unavailable</span>
|
||||
@endif
|
||||
@else
|
||||
<button type="button" class="btn btn-xs btn-info edit-btn"
|
||||
|
|
@ -399,6 +421,30 @@
|
|||
<!-- end container -->
|
||||
</div>
|
||||
<!-- end page -->
|
||||
|
||||
<div class="modal fade" id="tgics-validate-wa-modal" tabindex="-1" role="dialog" aria-labelledby="tgics-validate-wa-title" aria-hidden="true">
|
||||
<div class="modal-dialog modal-dialog-centered" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="tgics-validate-wa-title">Validate WhatsApp</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body text-center">
|
||||
<p class="mb-2" id="tgics-validate-wa-doctor"></p>
|
||||
<p class="text-muted small">Ask the doctor to scan this QR with the enrolled WhatsApp number and send the pre-filled message without changing it.</p>
|
||||
<div id="tgics-validate-wa-qr" class="d-flex justify-content-center my-3"></div>
|
||||
<p class="small mb-1" id="tgics-validate-wa-status">Waiting for validation…</p>
|
||||
<a href="#" id="tgics-validate-wa-open" target="_blank" rel="noopener noreferrer" class="btn btn-sm btn-outline-success">
|
||||
Open link instead
|
||||
</a>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style type="text/css">
|
||||
#pageloader {
|
||||
background: rgba(255, 255, 255, 0.8);
|
||||
|
|
@ -416,9 +462,23 @@
|
|||
position: absolute;
|
||||
top: 50%;
|
||||
}
|
||||
|
||||
#tgics-validate-wa-qr canvas,
|
||||
#tgics-validate-wa-qr img {
|
||||
max-width: 220px;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
#tgics-validate-wa-modal {
|
||||
z-index: 1055;
|
||||
}
|
||||
.tgics-validate-backdrop {
|
||||
z-index: 1050;
|
||||
}
|
||||
</style>
|
||||
@include('layouts.shared/footer-script')
|
||||
<script src="{{ asset('assets/libs/sweetalert2/sweetalert2.min.js') }}"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/qrcodejs/1.0.0/qrcode.min.js"></script>
|
||||
<script src="{{ asset('js/tgics-india-geo.js') }}"></script>
|
||||
<script type="text/javascript">
|
||||
jQuery(document).ready(function($) {
|
||||
|
|
@ -762,6 +822,140 @@
|
|||
$('#field-contact_id').trigger('change');
|
||||
});
|
||||
|
||||
var tgicsWaPollTimer = null;
|
||||
var tgicsWaPollStartedAt = 0;
|
||||
|
||||
function stopTgicsWaPoll() {
|
||||
if (tgicsWaPollTimer) {
|
||||
clearInterval(tgicsWaPollTimer);
|
||||
tgicsWaPollTimer = null;
|
||||
}
|
||||
}
|
||||
|
||||
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('<div class="modal-backdrop fade show tgics-validate-backdrop"></div>');
|
||||
}
|
||||
$('body').addClass('modal-open');
|
||||
}
|
||||
|
||||
function startTgicsWaPoll(contactId) {
|
||||
stopTgicsWaPoll();
|
||||
tgicsWaPollStartedAt = Date.now();
|
||||
$('#tgics-validate-wa-status').text('Waiting for validation…');
|
||||
|
||||
tgicsWaPollTimer = setInterval(function() {
|
||||
if (Date.now() - tgicsWaPollStartedAt > 120000) {
|
||||
stopTgicsWaPoll();
|
||||
$('#tgics-validate-wa-status').text('Still waiting. Close and try Validate again after the doctor sends the message.');
|
||||
return;
|
||||
}
|
||||
$.ajax({
|
||||
type: 'GET',
|
||||
url: '/form/tgicswhatsappstatus',
|
||||
data: {
|
||||
contact_id: contactId,
|
||||
partition: 'rapport-lifemankind'
|
||||
},
|
||||
success: function(res) {
|
||||
if (res && res.status === 'success' && res.data && res.data.validated) {
|
||||
stopTgicsWaPoll();
|
||||
$('#tgics-validate-wa-status').text('Validated!');
|
||||
Swal.fire({
|
||||
icon: 'success',
|
||||
title: 'WhatsApp validated',
|
||||
text: 'You can now send the survey link to this doctor.',
|
||||
timer: 1800,
|
||||
showConfirmButton: false
|
||||
}).then(function() {
|
||||
window.location.reload();
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}, 3000);
|
||||
}
|
||||
|
||||
$(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();
|
||||
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(
|
||||
'<p class="text-muted small mb-2">QR library unavailable. Use the button below.</p>'
|
||||
);
|
||||
}
|
||||
} catch (qrErr) {
|
||||
console.error(qrErr);
|
||||
$('#tgics-validate-wa-qr').html(
|
||||
'<p class="text-muted small mb-2">Unable to render QR. Use the button below.</p>'
|
||||
);
|
||||
}
|
||||
|
||||
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) {
|
||||
event.preventDefault();
|
||||
$("#pageloader").fadeIn();
|
||||
|
|
@ -808,28 +1002,27 @@
|
|||
today = yyyy + '-' + mm + '-' + dd;
|
||||
|
||||
var recordDateField = document.getElementById('field-plan_date');
|
||||
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');
|
||||
if (executionexeField && executionDateField && executionDateField.value) {
|
||||
executionexeField.setAttribute('min', executionDateField.value);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
if (executionDateField) {
|
||||
executionDateField.addEventListener('change', function() {
|
||||
console.log('gg');
|
||||
var executionexeField = document.getElementById('execution-record_date');
|
||||
if (executionexeField) {
|
||||
executionexeField.setAttribute('min', executionDateField.value);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
});
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -332,6 +332,7 @@ Route::get('/form/nebmitraverification', [FormController::class, 'nebmitraverifi
|
|||
|
||||
Route::get('/form/respidoctorsearch', [FormController::class, 'respidoctorsearch']);
|
||||
Route::get('/form/addrespidoctor', [FormController::class, 'addrespidoctor']);
|
||||
Route::get('/form/tgicswhatsappstatus', [FormController::class, 'tgicsWhatsappStatus']);
|
||||
|
||||
Route::post('/form/getformfielddata', [FormController::class, 'getformfielddata']);
|
||||
Route::post('/form/submit', [FormController::class, 'submit']);
|
||||
|
|
|
|||
Loading…
Reference in New Issue