=Live version

This commit is contained in:
Ravi Gulhane 2026-06-09 12:52:35 +05:30
parent 06ba160e4a
commit 3d05d7639f
67 changed files with 887 additions and 3134 deletions

1
CreastApp Submodule

@ -0,0 +1 @@
Subproject commit 9436f7a699484438f4beff38bf1c9a7372776fd2

View File

@ -26,7 +26,7 @@ class SendReminder extends Command
$sends = DB::table('message_reminder as ms') $sends = DB::table('message_reminder as ms')
->leftJoin('message_template as t', 'ms.template', '=', 't.id') ->leftJoin('message_template as t', 'ms.template', '=', 't.id')
->where('ms.status', 'active') ->where('ms.status', 'active')
->select('ms.*', 't.template_code', 't.template_body', 't.title as template_title') ->select('ms.*', 't.template_code', 't.template_body', 't.title as template_title', 't.button_url', 't.button_label')
->get(); ->get();
$sessions = DB::table('sessions') $sessions = DB::table('sessions')
@ -62,23 +62,28 @@ class SendReminder extends Command
[ [
'source' => 'dynamodb', 'source' => 'dynamodb',
'search' => json_encode($searchparam), 'search' => json_encode($searchparam),
'fields' => json_encode(['session_code', 'email', 'name', 'phone', 'id']), 'start' => 0,
'length' => 9999,
], ],
env('LAMBDA_ACCESS_TOKEN', 'default_value') env('LAMBDA_ACCESS_TOKEN', 'default_value')
); );
if (sizeof($response->data->items) > 0) { $contacts = SessionCommunicationService::extractContactItems($response);
if (count($contacts) > 0) {
$config = [ $config = [
'id' => $send->id, 'id' => $send->id,
'template_code' => $send->template_code, 'template_code' => $send->template_code,
'template_body' => $send->template_body, 'template_body' => $send->template_body,
'template_title' => $send->template_title, 'template_title' => $send->template_title,
'button_url' => $send->button_url,
'button_label' => $send->button_label,
'header_params' => $send->header_params, 'header_params' => $send->header_params,
'body_params' => $send->body_params, 'body_params' => $send->body_params,
'button_params' => $send->button_params, 'button_params' => $send->button_params,
]; ];
foreach ($response->data->items as $item) { foreach ($contacts as $item) {
$this->comm->dispatchForContact($session, $item, $config); $this->comm->dispatchForContact($session, $item, $config);
} }
} }

View File

@ -3,6 +3,7 @@
namespace App\Console\Commands; namespace App\Console\Commands;
use App\Http\Requests\LambdaRequest; use App\Http\Requests\LambdaRequest;
use App\Models\Session;
use App\Services\SessionCommunicationService; use App\Services\SessionCommunicationService;
use Illuminate\Console\Command; use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\DB;
@ -29,6 +30,18 @@ class Sendwhatsapp extends Command
$sends = DB::table('raphiwa_send')->where('is_sent', 0)->limit(30)->get(); $sends = DB::table('raphiwa_send')->where('is_sent', 0)->limit(30)->get();
if ($sends->count() > 0) { if ($sends->count() > 0) {
foreach ($sends as $send) { foreach ($sends as $send) {
if ($send->session_id > 0) {
$mode = $this->comm->resolveMode((int) $send->session_id);
if (!$this->comm->shouldSendWhatsApp($mode)) {
DB::table('raphiwa_send')->where('id', $send->id)->update([
'is_sent' => 1,
'response' => 'skipped_email_only_session',
'updated_at' => now(),
]);
continue;
}
}
$resp = Http::withHeaders(['Authorization' => $auth]) $resp = Http::withHeaders(['Authorization' => $auth])
->post('https://api.interakt.ai/v1/public/message/', (array) json_decode($send->text)); ->post('https://api.interakt.ai/v1/public/message/', (array) json_decode($send->text));
$respj = json_decode($resp->getBody()); $respj = json_decode($resp->getBody());
@ -65,6 +78,8 @@ class Sendwhatsapp extends Command
't.template_code', 't.template_code',
't.template_body', 't.template_body',
't.title as template_title', 't.title as template_title',
't.button_url',
't.button_label',
'ms.header_params', 'ms.header_params',
'ms.body_params', 'ms.body_params',
'ms.button_params', 'ms.button_params',
@ -88,24 +103,30 @@ class Sendwhatsapp extends Command
[ [
'source' => 'dynamodb', 'source' => 'dynamodb',
'search' => json_encode($searchparam), 'search' => json_encode($searchparam),
'fields' => json_encode(['session_code', 'email', 'name', 'phone', 'id']), 'start' => 0,
'length' => 9999,
], ],
env('LAMBDA_ACCESS_TOKEN', 'default_value') env('LAMBDA_ACCESS_TOKEN', 'default_value')
); );
if (sizeof($response->data->items) > 0) { $sessionModel = Session::find($send->session_id);
$contacts = SessionCommunicationService::extractContactItems($response);
if ($sessionModel && count($contacts) > 0) {
$config = [ $config = [
'id' => $send->id, 'id' => $send->id,
'template_code' => $send->template_code, 'template_code' => $send->template_code,
'template_body' => $send->template_body, 'template_body' => $send->template_body,
'template_title' => $send->template_title, 'template_title' => $send->template_title,
'button_url' => $send->button_url,
'button_label' => $send->button_label,
'header_params' => $send->header_params, 'header_params' => $send->header_params,
'body_params' => $send->body_params, 'body_params' => $send->body_params,
'button_params' => $send->button_params, 'button_params' => $send->button_params,
]; ];
foreach ($response->data->items as $item) { foreach ($contacts as $item) {
$this->comm->dispatchForContact($send, $item, $config); $this->comm->dispatchForContact($sessionModel, $item, $config);
} }
} }

View File

@ -122,13 +122,18 @@ class MicrositeController extends LocalController
public function register($code, Request $request) public function register($code, Request $request)
{ {
$session = (object)Session::where('code', $code)->first()->toArray(); $sessionModel = Session::where('code', $code)->first();
$session = (object) $sessionModel->toArray();
$linked_user = $request->input('linked_user', false); $linked_user = $request->input('linked_user', false);
$session->dates = json_decode($session->dates); $session->dates = json_decode($session->dates);
$request->session()->put('session_type', $session->type); $request->session()->put('session_type', $session->type);
$request->session()->put('linked_user', $linked_user); $request->session()->put('linked_user', $linked_user);
//echo $session->type; exit; $comm = app(SessionCommunicationService::class);
return view($session->type . '.register', ['session' => $session]);
return view($session->type . '.register', [
'session' => $session,
'communication_mode' => $comm->resolveMode($sessionModel),
]);
} }
public function postregister($code, Request $request) public function postregister($code, Request $request)

View File

@ -42,7 +42,7 @@ class MsgreminderController extends LocalController
foreach($sessions as $session){ foreach($sessions as $session){
$session_bb[$session->id] = $session->type.' ('.$session->number.') '. date("d-m-Y", strtotime($session->start_date)) . ' (' . $session->venue. ')'; $session_bb[$session->id] = $session->type.' ('.$session->number.') '. date("d-m-Y", strtotime($session->start_date)) . ' (' . $session->venue. ')';
} }
$data = MessageTemplate::where('status', 'active')->select('id', 'title', 'template_body', 'template_code', 'header_params', 'body_params', 'button_params')->get(); $data = MessageTemplate::where('status', 'active')->select('id', 'title', 'template_body', 'template_code', 'header_params', 'body_params', 'button_params', 'button_url', 'button_label')->get();
$templates = []; $templates = [];
$template_data = []; $template_data = [];
foreach($data as $d) { foreach($data as $d) {
@ -57,6 +57,7 @@ class MsgreminderController extends LocalController
'header_params' => ['title' => 'Header Params (only if changes needed)', 'type' => 'keywords', 'fullwidth' => true], 'header_params' => ['title' => 'Header Params (only if changes needed)', 'type' => 'keywords', 'fullwidth' => true],
'body_params' => ['title' => 'Body Params (only if changes needed)', 'type' => 'keywords', 'fullwidth' => true], 'body_params' => ['title' => 'Body Params (only if changes needed)', 'type' => 'keywords', 'fullwidth' => true],
'button_params' => ['title' => 'Button Params (only if changes needed)', 'type' => 'keywords', 'fullwidth' => true], 'button_params' => ['title' => 'Button Params (only if changes needed)', 'type' => 'keywords', 'fullwidth' => true],
'button_cta' => ['title' => 'Email CTA (from template)', 'type' => 'keywords', 'fullwidth' => true],
'days_before' => ['title' => 'Days Before', 'type' => 'number', 'required' => true], 'days_before' => ['title' => 'Days Before', 'type' => 'number', 'required' => true],
'time' => ['title' => 'Time of Day', 'type' => 'time', 'required' => true], 'time' => ['title' => 'Time of Day', 'type' => 'time', 'required' => true],
'audience' => ['title' => 'Audience', 'type' => 'select', 'values' => ['all' => 'All', 'attended' => 'Only Attended'] , 'required' => true], 'audience' => ['title' => 'Audience', 'type' => 'select', 'values' => ['all' => 'All', 'attended' => 'Only Attended'] , 'required' => true],

View File

@ -79,7 +79,7 @@ class MsgsendController extends LocalController
$session_bb[$session->id] = $session->type.' ('.$session->number.') '. date("d-m-Y", strtotime($session->start_date)) . ' (' . $session->venue. ')'; $session_bb[$session->id] = $session->type.' ('.$session->number.') '. date("d-m-Y", strtotime($session->start_date)) . ' (' . $session->venue. ')';
} }
$data = MessageTemplate::where('status', 'active')->select('id', 'title', 'template_body', 'template_code', 'header_params', 'body_params', 'button_params')->get(); $data = MessageTemplate::where('status', 'active')->select('id', 'title', 'template_body', 'template_code', 'header_params', 'body_params', 'button_params', 'button_url', 'button_label')->get();
$templates = []; $templates = [];
$template_data = []; $template_data = [];
foreach($data as $d) { foreach($data as $d) {
@ -94,6 +94,7 @@ class MsgsendController extends LocalController
'header_params' => ['title' => 'Header Params (only if changes needed)', 'type' => 'keywords', 'fullwidth' => true], 'header_params' => ['title' => 'Header Params (only if changes needed)', 'type' => 'keywords', 'fullwidth' => true],
'body_params' => ['title' => 'Body Params (only if changes needed)', 'type' => 'keywords', 'fullwidth' => true], 'body_params' => ['title' => 'Body Params (only if changes needed)', 'type' => 'keywords', 'fullwidth' => true],
'button_params' => ['title' => 'Button Params (only if changes needed)', 'type' => 'keywords', 'fullwidth' => true], 'button_params' => ['title' => 'Button Params (only if changes needed)', 'type' => 'keywords', 'fullwidth' => true],
'button_cta' => ['title' => 'Email CTA (from template)', 'type' => 'keywords', 'fullwidth' => true],
'audience' => ['title' => 'Audience', 'type' => 'select', 'values' => ['all' => 'All', 'attended' => 'Only Attended'] , 'required' => true], 'audience' => ['title' => 'Audience', 'type' => 'select', 'values' => ['all' => 'All', 'attended' => 'Only Attended'] , 'required' => true],
'status' => ['title' => 'Status', 'type' => 'select', 'required' => true, 'values' => ['active' => 'Active', 'disabled' => 'Disabled'] ], 'status' => ['title' => 'Status', 'type' => 'select', 'required' => true, 'values' => ['active' => 'Active', 'disabled' => 'Disabled'] ],
]; ];

View File

@ -40,8 +40,9 @@ class MsgtemplateController extends LocalController
'template_body' => ['title' => 'Template Body', 'type' => 'textarea', 'required' => true, 'fullwidth' => true], 'template_body' => ['title' => 'Template Body', 'type' => 'textarea', 'required' => true, 'fullwidth' => true],
'header_params' => ['title' => 'Header Params', 'type' => 'textarea', 'fullwidth' => true], 'header_params' => ['title' => 'Header Params', 'type' => 'textarea', 'fullwidth' => true],
'body_params' => ['title' => 'Body Params', 'type' => 'textarea', 'fullwidth' => true], 'body_params' => ['title' => 'Body Params', 'type' => 'textarea', 'fullwidth' => true],
'button_params' => ['title' => 'Button Params', 'type' => 'textarea', 'fullwidth' => true], 'button_params' => ['title' => 'Button Params (WhatsApp)', 'type' => 'textarea', 'fullwidth' => true],
//'email_body' => ['title' => 'Email Body', 'type' => 'textarea', 'required' => true, 'fullwidth' => true], 'button_url' => ['title' => 'Button URL (Email)', 'type' => 'text', 'fullwidth' => true, 'placeholder' => 'road.xltr.in/brochure/{{1}} or {{SESSION_CODE}}'],
'button_label' => ['title' => 'Button Label (Email)', 'type' => 'text', 'fullwidth' => true, 'placeholder' => 'Complete feedback'],
'status' => ['title' => 'Status', 'type' => 'select', 'required' => true, 'values' => ['active' => 'Active', 'disabled' => 'Disabled'] ], 'status' => ['title' => 'Status', 'type' => 'select', 'required' => true, 'values' => ['active' => 'Active', 'disabled' => 'Disabled'] ],
]; ];
return $fields; return $fields;

View File

@ -0,0 +1,39 @@
<?php
namespace App\Http\Controllers;
use App\Services\RegisterLocationService;
use Illuminate\Http\Request;
class RegisterLocationController extends Controller
{
public function countries()
{
$paths = [
storage_path('app/geo/countriesAndStates.json'),
public_path('assets/data/countriesAndStates.json'),
public_path('data/countriesAndStates.json'),
];
foreach ($paths as $path) {
if (is_readable($path)) {
return response()->file($path, [
'Content-Type' => 'application/json; charset=UTF-8',
'Cache-Control' => 'public, max-age=86400',
]);
}
}
return response()->json(['error' => 'Countries data not found'], 404);
}
public function cities(Request $request, RegisterLocationService $locations)
{
$country = (string) $request->query('country', '');
$state = (string) $request->query('state', '');
return response()->json(
$locations->getCitiesForCountryState($country, $state)
);
}
}

View File

@ -26,6 +26,8 @@ class MessageTemplate extends Model
'header_params', 'header_params',
'body_params', 'body_params',
'button_params', 'button_params',
'button_url',
'button_label',
'status', 'status',
]; ];
} }

View File

@ -0,0 +1,130 @@
<?php
namespace App\Services;
class RegisterLocationService
{
private const SIGNUP_COUNTRY_TO_CSC_NAME = [
'Antigua and Barbuda' => 'Antigua And Barbuda',
'Eswatini' => 'Swaziland',
'Guernsey' => 'Guernsey and Alderney',
'Ivory Coast' => "Cote D'Ivoire (Ivory Coast)",
'North Macedonia' => 'Macedonia',
'Papua New Guinea' => 'Papua new Guinea',
'Saint Kitts and Nevis' => 'Saint Kitts And Nevis',
'Saint Vincent and the Grenadines' => 'Saint Vincent And The Grenadines',
'Svalbard and Jan Mayen Islands' => 'Svalbard And Jan Mayen Islands',
'Timor-Leste' => 'East Timor',
'Trinidad and Tobago' => 'Trinidad And Tobago',
'Turks and Caicos Islands' => 'Turks And Caicos Islands',
'Wallis and Futuna Islands' => 'Wallis And Futuna Islands',
];
private static $countries;
private static $states;
private static $cities;
public function getCitiesForCountryState(string $countryName, string $stateName): array
{
$countryName = trim($countryName);
$stateName = trim($stateName);
if ($countryName === '' || $stateName === '') {
return [];
}
$countryCode = $this->resolveCountryCode($countryName);
if (!$countryCode) {
return [];
}
$stateCode = $this->resolveStateCode($countryCode, $stateName);
if (!$stateCode) {
return [];
}
$names = [];
foreach ($this->loadCities() as $row) {
if (!is_array($row) || count($row) < 3) {
continue;
}
if (($row[1] ?? '') === $countryCode && ($row[2] ?? '') === $stateCode) {
$names[] = $row[0];
}
}
$names = array_values(array_unique($names));
sort($names, SORT_STRING);
return $names;
}
private function resolveCountryCode(string $countryName): ?string
{
$lookup = self::SIGNUP_COUNTRY_TO_CSC_NAME[$countryName] ?? $countryName;
foreach ($this->loadCountries() as $country) {
if (!is_array($country)) {
continue;
}
$name = $country['name'] ?? '';
if ($name === $lookup || $name === $countryName) {
return $country['isoCode'] ?? null;
}
}
return null;
}
private function resolveStateCode(string $countryCode, string $stateName): ?string
{
foreach ($this->loadStates() as $state) {
if (!is_array($state)) {
continue;
}
if (($state['countryCode'] ?? '') === $countryCode && ($state['name'] ?? '') === $stateName) {
return $state['isoCode'] ?? null;
}
}
return null;
}
private function loadCountries(): array
{
if (self::$countries === null) {
self::$countries = $this->readJson('country.json');
}
return self::$countries;
}
private function loadStates(): array
{
if (self::$states === null) {
self::$states = $this->readJson('state.json');
}
return self::$states;
}
private function loadCities(): array
{
if (self::$cities === null) {
self::$cities = $this->readJson('city.json');
}
return self::$cities;
}
private function readJson(string $filename): array
{
$path = storage_path('app/geo/' . $filename);
if (!is_readable($path)) {
return [];
}
$decoded = json_decode(file_get_contents($path), true);
return is_array($decoded) ? $decoded : [];
}
}

View File

@ -2,11 +2,15 @@
namespace App\Services; namespace App\Services;
use App\Http\Requests\LambdaRequest;
use App\Models\Session; use App\Models\Session;
use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
class SessionCommunicationService class SessionCommunicationService
{ {
public const EMAIL_SUBJECT_PREFIX = 'CREST Research and Training Support';
protected static $feedbackTemplateCodes = [ protected static $feedbackTemplateCodes = [
'crest_thankyou_and_feedback', 'crest_thankyou_and_feedback',
'crest_feedback_new', 'crest_feedback_new',
@ -14,17 +18,88 @@ class SessionCommunicationService
'pre_impact_assessment', 'pre_impact_assessment',
]; ];
/**
* Normalize Lambda contact/get_all response items to a foreach-safe array.
*/
public static function extractContactItems($response): array
{
if (!is_object($response) || !isset($response->data)) {
return [];
}
if (!isset($response->data->items)) {
return [];
}
$items = $response->data->items;
if (is_array($items)) {
return $items;
}
if (!is_object($items)) {
return [];
}
// Single contact object stored in items (not a list wrapper).
if (isset($items->id) && (isset($items->phone) || isset($items->name) || isset($items->email))) {
return [$items];
}
return array_values((array) $items);
}
public function resolveSessionForMode($session): ?Session
{
if ($session instanceof Session) {
return $session;
}
if (is_numeric($session)) {
return Session::find((int) $session);
}
if (!is_object($session)) {
return null;
}
if (!empty($session->session_id)) {
$loaded = Session::find($session->session_id);
if ($loaded) {
return $loaded;
}
}
if (!empty($session->code)) {
$loaded = Session::where('code', $session->code)->first();
if ($loaded) {
return $loaded;
}
}
if (!empty($session->id) && empty($session->template_code ?? null)) {
return Session::find($session->id);
}
return null;
}
public function resolveMode($session): string public function resolveMode($session): string
{ {
if (!$session) { $sessionModel = $this->resolveSessionForMode($session);
if (!$sessionModel) {
if (is_object($session) && !empty($session->communication_mode)) {
$mode = strtolower(trim((string) $session->communication_mode));
if (in_array($mode, [Session::MODE_WHATSAPP, Session::MODE_EMAIL, Session::MODE_BOTH], true)) {
return $mode;
}
}
return Session::MODE_WHATSAPP; return Session::MODE_WHATSAPP;
} }
$mode = is_object($session) $mode = strtolower(trim((string) ($sessionModel->communication_mode ?? '')));
? ($session->communication_mode ?? null)
: ($session['communication_mode'] ?? null);
$mode = strtolower(trim((string) $mode));
if (!in_array($mode, [Session::MODE_WHATSAPP, Session::MODE_EMAIL, Session::MODE_BOTH], true)) { if (!in_array($mode, [Session::MODE_WHATSAPP, Session::MODE_EMAIL, Session::MODE_BOTH], true)) {
return Session::MODE_WHATSAPP; return Session::MODE_WHATSAPP;
@ -33,6 +108,20 @@ class SessionCommunicationService
return $mode; return $mode;
} }
public function resolveSessionId($session): int
{
$sessionModel = $this->resolveSessionForMode($session);
if ($sessionModel) {
return (int) $sessionModel->id;
}
if (is_object($session)) {
return (int) ($session->session_id ?? $session->id ?? 0);
}
return (int) ($session['session_id'] ?? $session['id'] ?? 0);
}
public function shouldSendWhatsApp(string $mode): bool public function shouldSendWhatsApp(string $mode): bool
{ {
return in_array($mode, [Session::MODE_WHATSAPP, Session::MODE_BOTH], true); return in_array($mode, [Session::MODE_WHATSAPP, Session::MODE_BOTH], true);
@ -56,7 +145,8 @@ class SessionCommunicationService
public function buildSessionVariables($session, $sendRow = null): array public function buildSessionVariables($session, $sendRow = null): array
{ {
$session = is_object($session) ? $session : (object) $session; $sessionModel = $this->resolveSessionForMode($session);
$session = $sessionModel ?: (is_object($session) ? $session : (object) $session);
return [ return [
'SESSION_NAME' => $session->number ?? '', 'SESSION_NAME' => $session->number ?? '',
@ -95,11 +185,21 @@ class SessionCommunicationService
$sendId = is_object($sendRow) ? ($sendRow->id ?? 0) : ($sendRow['id'] ?? 0); $sendId = is_object($sendRow) ? ($sendRow->id ?? 0) : ($sendRow['id'] ?? 0);
return array_merge($sessionVars, [ $vars = array_merge($sessionVars, [
'SESSION_CODE' => $sessionCode, 'SESSION_CODE' => $sessionCode,
'RECIPIENT_NAME' => is_object($contact) ? ($contact->name ?? '') : ($contact['name'] ?? ''), 'RECIPIENT_NAME' => is_object($contact) ? ($contact->name ?? '') : ($contact['name'] ?? ''),
'CERT_PARAM' => (is_object($contact) ? ($contact->phone ?? '') : ($contact['phone'] ?? '')) . '_' . $sendId, 'CERT_PARAM' => (is_object($contact) ? ($contact->phone ?? '') : ($contact['phone'] ?? '')) . '_' . $sendId,
]); ]);
if (is_object($contact)) {
foreach (get_object_vars($contact) as $key => $value) {
if (is_string($key) && $key !== '' && !is_array($value) && !is_object($value)) {
$vars[strtoupper($key)] = (string) $value;
}
}
}
return $vars;
} }
public function substituteParams(?string $pipeList, array $vars): array public function substituteParams(?string $pipeList, array $vars): array
@ -118,7 +218,7 @@ class SessionCommunicationService
return $params; return $params;
} }
public function renderTemplateBody(string $body, array $vars): string public function renderTemplateBody(string $body, array $vars, array $numericValues = []): string
{ {
$rendered = $body; $rendered = $body;
@ -127,9 +227,31 @@ class SessionCommunicationService
$rendered = str_replace('{' . $key . '}', $value, $rendered); $rendered = str_replace('{' . $key . '}', $value, $rendered);
} }
foreach ($numericValues as $index => $value) {
$placeholder = '{{' . ($index + 1) . '}}';
$rendered = str_replace($placeholder, (string) $value, $rendered);
}
return $rendered; return $rendered;
} }
/**
* Ensure absolute URLs (e.g. road.xltr.in/path → https://road.xltr.in/path).
*/
public function normalizeUrlScheme(string $url): string
{
$url = trim($url);
if ($url === '') {
return '';
}
if (!preg_match('#^https?://#i', $url)) {
$url = 'https://' . ltrim($url, '/');
}
return $url;
}
public function buildButtonSection(array $buttonValues): string public function buildButtonSection(array $buttonValues): string
{ {
if (empty($buttonValues)) { if (empty($buttonValues)) {
@ -152,6 +274,52 @@ class SessionCommunicationService
return implode("\n", $lines); return implode("\n", $lines);
} }
/**
* Build email CTA button from template button_url / button_label + substituted params.
*/
public function buildEmailCallToAction(array $config, array $vars, array $buttonParamValues = []): string
{
$urlTemplate = trim($config['button_url'] ?? '');
$label = trim($config['button_label'] ?? '');
if ($urlTemplate === '') {
return '';
}
$url = $this->renderTemplateBody($urlTemplate, $vars, $buttonParamValues);
$url = $this->normalizeUrlScheme($url);
if (!filter_var($url, FILTER_VALIDATE_URL)) {
$paramValue = trim((string) ($buttonParamValues[0] ?? ''));
if ($paramValue !== '' && filter_var($this->normalizeUrlScheme($paramValue), FILTER_VALIDATE_URL)) {
$url = $this->normalizeUrlScheme($paramValue);
} elseif ($paramValue !== '') {
$base = $this->normalizeUrlScheme(
$this->renderTemplateBody(rtrim($urlTemplate, '/'), $vars, $buttonParamValues)
);
$url = rtrim($base, '/') . '/' . ltrim($paramValue, '/');
}
}
$url = $this->normalizeUrlScheme($url);
if ($url === '' || !filter_var($url, FILTER_VALIDATE_URL)) {
return '';
}
if ($label === '') {
$label = 'Click here';
}
$label = $this->renderTemplateBody($label, $vars, $buttonParamValues);
return '<table role="presentation" cellspacing="0" cellpadding="0" border="0" style="margin:28px auto 8px;">'
. '<tr><td align="center" style="border-radius:6px;background-color:#1a3a5c;">'
. '<a href="' . e($url) . '" target="_blank" rel="noopener noreferrer" '
. 'style="display:inline-block;padding:14px 28px;font-size:15px;font-weight:bold;color:#ffffff;text-decoration:none;">'
. e($label)
. '</a></td></tr></table>';
}
public function buildInteraktTemplate(array $config, array $vars): array public function buildInteraktTemplate(array $config, array $vars): array
{ {
if (!empty($config['header_values']) && is_array($config['header_values'])) { if (!empty($config['header_values']) && is_array($config['header_values'])) {
@ -181,10 +349,9 @@ class SessionCommunicationService
return $template; return $template;
} }
public function buildEmailBody(string $templateBody, array $vars, array $buttonValues = [], array $headerValues = []): string public function buildEmailBody(string $templateBody, array $vars, array $buttonValues = [], array $headerValues = [], array $numericValues = [], array $config = []): string
{ {
$body = $this->renderTemplateBody($templateBody, $vars); $body = $this->renderTemplateBody($templateBody, $vars, $numericValues);
$body .= $this->buildButtonSection($buttonValues);
$imageHtml = ''; $imageHtml = '';
foreach ($headerValues as $headerValue) { foreach ($headerValues as $headerValue) {
@ -193,31 +360,83 @@ class SessionCommunicationService
} }
} }
return $imageHtml . nl2br(e($body)); $ctaHtml = $this->buildEmailCallToAction($config, $vars, $buttonValues);
if ($ctaHtml === '') {
$body .= $this->buildButtonSection($buttonValues);
}
return $imageHtml . nl2br(e($body)) . $ctaHtml;
} }
public function buildEmailSubject($session, $sendRow): string public function buildEmailSubject($session, $sendRow): string
{ {
$sessionName = is_object($session) ? ($session->number ?? 'Crest Session') : ($session['number'] ?? 'Crest Session'); $sessionName = is_object($session) ? ($session->number ?? 'Session') : ($session['number'] ?? 'Session');
$title = is_object($sendRow) ? ($sendRow->template_title ?? null) : ($sendRow['template_title'] ?? null); $title = is_object($sendRow) ? ($sendRow->template_title ?? null) : ($sendRow['template_title'] ?? null);
$prefix = self::EMAIL_SUBJECT_PREFIX;
if (!empty($title)) { if (!empty($title)) {
return 'Crest – ' . $title; return $prefix . ' – ' . $title;
} }
return 'Crest – ' . $sessionName; return $prefix . ' – ' . $sessionName;
} }
public function contactEmail($contact): ?string public function contactEmail($contact): ?string
{ {
$email = is_object($contact) ? ($contact->email ?? '') : ($contact['email'] ?? ''); $candidates = [];
$email = trim((string) $email); if (is_object($contact)) {
$candidates = [
if ($email === '' || !filter_var($email, FILTER_VALIDATE_EMAIL)) { $contact->email ?? null,
return null; $contact->user_email ?? null,
$contact->Email ?? null,
];
} elseif (is_array($contact)) {
$candidates = [
$contact['email'] ?? null,
$contact['user_email'] ?? null,
];
} }
return $email; foreach ($candidates as $email) {
$email = trim((string) $email);
if ($email !== '' && filter_var($email, FILTER_VALIDATE_EMAIL)) {
return $email;
}
}
return null;
}
/**
* Load full contact from Lambda when get_all omitted email (fields projection).
*/
public function enrichContactEmail($contact)
{
if ($this->contactEmail($contact)) {
return $contact;
}
$contactId = is_object($contact) ? ($contact->id ?? null) : ($contact['id'] ?? null);
if (!$contactId) {
return $contact;
}
try {
$response = LambdaRequest::getrequest(
'contact',
'contact/get_one',
['id' => $contactId],
env('LAMBDA_ACCESS_TOKEN', 'default_value')
);
if (!empty($response->data->item->email) && is_object($contact)) {
$contact->email = $response->data->item->email;
}
} catch (\Throwable $e) {
Log::warning('enrichContactEmail failed for contact ' . $contactId . ': ' . $e->getMessage());
}
return $contact;
} }
public function queueWhatsApp($contact, int $sessionId, array $interaktPayload): void public function queueWhatsApp($contact, int $sessionId, array $interaktPayload): void
@ -239,8 +458,14 @@ class SessionCommunicationService
public function queueEmail($contact, int $sessionId, string $subject, string $bodyHtml, ?string $templateCode = null): bool public function queueEmail($contact, int $sessionId, string $subject, string $bodyHtml, ?string $templateCode = null): bool
{ {
$contact = $this->enrichContactEmail($contact);
$email = $this->contactEmail($contact); $email = $this->contactEmail($contact);
if (!$email) { if (!$email) {
$contactId = is_object($contact) ? ($contact->id ?? 'unknown') : 'unknown';
Log::info('email_send skipped: no valid email on contact', [
'contact_id' => $contactId,
'session_id' => $sessionId,
]);
return false; return false;
} }
@ -277,9 +502,10 @@ class SessionCommunicationService
public function dispatchForContact($session, $contact, array $config): void public function dispatchForContact($session, $contact, array $config): void
{ {
$sessionModel = $this->resolveSessionForMode($session);
$mode = $this->resolveMode($session); $mode = $this->resolveMode($session);
$sessionId = is_object($session) ? (int) ($session->id ?? 0) : (int) ($session['id'] ?? 0); $sessionId = $this->resolveSessionId($session);
$vars = $this->buildContactVariables($contact, $session, $config); $vars = $this->buildContactVariables($contact, $sessionModel ?: $session, $config);
if (!empty($config['header_values']) && is_array($config['header_values'])) { if (!empty($config['header_values']) && is_array($config['header_values'])) {
$headerParams = $config['header_values']; $headerParams = $config['header_values'];
@ -307,10 +533,10 @@ class SessionCommunicationService
} }
if ($this->shouldSendEmail($mode)) { if ($this->shouldSendEmail($mode)) {
$templateBody = $config['template_body'] ?? ''; $templateBody = trim($config['template_body'] ?? '');
if ($templateBody !== '') { if ($templateBody !== '') {
$bodyHtml = $this->buildEmailBody($templateBody, $vars, $buttonParams, $headerParams); $bodyHtml = $this->buildEmailBody($templateBody, $vars, $buttonParams, $headerParams, $bodyParams, $config);
$subject = $this->buildEmailSubject($session, $config); $subject = $this->buildEmailSubject($sessionModel ?: $session, $config);
$this->queueEmail( $this->queueEmail(
$contact, $contact,
$sessionId, $sessionId,
@ -318,6 +544,11 @@ class SessionCommunicationService
$bodyHtml, $bodyHtml,
$config['template_code'] ?? null $config['template_code'] ?? null
); );
} else {
Log::warning('email_send skipped: empty template_body', [
'session_id' => $sessionId,
'template_code' => $config['template_code'] ?? null,
]);
} }
} }
} }

View File

@ -0,0 +1,40 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class AddButtonUrlLabelToMessageTemplate extends Migration
{
public function up()
{
if (Schema::hasTable('message_template')) {
if (!Schema::hasColumn('message_template', 'button_url')) {
Schema::table('message_template', function (Blueprint $table) {
$table->string('button_url', 500)->nullable()->after('button_params');
});
}
if (!Schema::hasColumn('message_template', 'button_label')) {
Schema::table('message_template', function (Blueprint $table) {
$table->string('button_label', 255)->nullable()->after('button_url');
});
}
}
}
public function down()
{
if (Schema::hasTable('message_template')) {
if (Schema::hasColumn('message_template', 'button_label')) {
Schema::table('message_template', function (Blueprint $table) {
$table->dropColumn('button_label');
});
}
if (Schema::hasColumn('message_template', 'button_url')) {
Schema::table('message_template', function (Blueprint $table) {
$table->dropColumn('button_url');
});
}
}
}
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,220 @@
/**
* Dependent country → state → city dropdowns for registration forms.
*/
(function () {
'use strict';
var CITIES_URL =
(typeof window !== 'undefined' && window.REGISTER_LOCATION_CITIES_URL) ||
'/geo/cities';
var countriesData = null;
function isValidCountriesMap(data) {
return (
data &&
typeof data === 'object' &&
!Array.isArray(data) &&
Object.keys(data).length > 0
);
}
function loadCountriesData() {
if (isValidCountriesMap(countriesData)) {
return Promise.resolve(countriesData);
}
if (isValidCountriesMap(window.REGISTER_LOCATION_COUNTRIES)) {
countriesData = window.REGISTER_LOCATION_COUNTRIES;
return Promise.resolve(countriesData);
}
return fetch('/geo/countries', { credentials: 'same-origin' })
.then(function (res) {
if (!res.ok) {
throw new Error('Failed to load countries data');
}
var ct = res.headers.get('content-type') || '';
if (ct.indexOf('json') === -1) {
throw new Error('Countries data returned non-JSON response');
}
return res.json();
})
.then(function (data) {
if (!isValidCountriesMap(data)) {
throw new Error('Countries data is empty or invalid');
}
countriesData = data;
return data;
});
}
function loadCities(country, state) {
var url =
CITIES_URL +
'?country=' +
encodeURIComponent(country) +
'&state=' +
encodeURIComponent(state);
function fetchCitiesFrom(endpoint) {
return fetch(endpoint, { credentials: 'same-origin' }).then(function (res) {
if (!res.ok) {
throw new Error('Failed to load cities');
}
var ct = res.headers.get('content-type') || '';
if (ct.indexOf('json') === -1) {
throw new Error('Cities endpoint returned non-JSON response');
}
return res.json();
});
}
return fetchCitiesFrom(url).catch(function () {
if (url.indexOf('/api/geo/cities') === -1) {
return fetchCitiesFrom('/api/geo/cities' + url.substring(url.indexOf('?')));
}
throw new Error('Failed to load cities');
}).then(function (data) {
return Array.isArray(data) ? data : [];
});
}
function fillSelect(select, options, placeholder) {
select.innerHTML = '';
var empty = document.createElement('option');
empty.value = '';
empty.textContent = placeholder;
select.appendChild(empty);
options.forEach(function (opt) {
var el = document.createElement('option');
el.value = opt;
el.textContent = opt;
select.appendChild(el);
});
}
function setCityMode(selectEl, inputEl, cityFieldName, mode, cities) {
cities = cities || [];
if (mode === 'select' && cities.length > 0) {
selectEl.style.display = '';
inputEl.style.display = 'none';
inputEl.removeAttribute('name');
inputEl.disabled = true;
inputEl.required = false;
selectEl.setAttribute('name', cityFieldName);
selectEl.disabled = false;
selectEl.required = true;
fillSelect(selectEl, cities, '-- Select City --');
} else {
selectEl.style.display = 'none';
inputEl.style.display = '';
selectEl.removeAttribute('name');
selectEl.disabled = true;
selectEl.required = false;
selectEl.value = '';
inputEl.setAttribute('name', cityFieldName);
inputEl.disabled = false;
inputEl.required = true;
inputEl.placeholder =
mode === 'select'
? 'Enter city (no list available for this state)'
: 'Enter city';
if (mode !== 'select') {
inputEl.value = '';
}
}
}
function initRegisterLocationDropdowns() {
var wrapper = document.querySelector('.register-location-fields');
var countrySelect = document.getElementById('country');
var stateSelect = document.getElementById('state');
var citySelect = document.getElementById('city');
var cityInput = document.querySelector('.register-location-city-input');
if (!wrapper || !countrySelect || !stateSelect || !citySelect || !cityInput) {
return Promise.resolve();
}
var cityFieldName = wrapper.getAttribute('data-city-field') || 'city';
return loadCountriesData().then(function (data) {
var countries = Object.keys(data).sort(function (a, b) {
return a.localeCompare(b);
});
fillSelect(countrySelect, countries, '-- Select Country --');
var defaultCountry = wrapper.getAttribute('data-default-country') || 'India';
if (defaultCountry && data[defaultCountry]) {
countrySelect.value = defaultCountry;
fillSelect(stateSelect, data[defaultCountry], '-- Select State --');
stateSelect.disabled = false;
}
countrySelect.addEventListener('change', function () {
var country = countrySelect.value;
stateSelect.value = '';
citySelect.value = '';
cityInput.value = '';
setCityMode(citySelect, cityInput, cityFieldName, 'input');
citySelect.disabled = true;
cityInput.disabled = true;
if (!country || !data[country]) {
fillSelect(stateSelect, [], '-- Select State --');
stateSelect.disabled = true;
return;
}
fillSelect(stateSelect, data[country], '-- Select State --');
stateSelect.disabled = false;
});
stateSelect.addEventListener('change', function () {
var country = countrySelect.value;
var state = stateSelect.value;
citySelect.value = '';
cityInput.value = '';
if (!country || !state) {
setCityMode(citySelect, cityInput, cityFieldName, 'input');
citySelect.disabled = true;
cityInput.disabled = true;
return;
}
cityInput.disabled = true;
citySelect.disabled = true;
loadCities(country, state)
.then(function (cities) {
if (cities.length > 0) {
setCityMode(citySelect, cityInput, cityFieldName, 'select', cities);
} else {
setCityMode(citySelect, cityInput, cityFieldName, 'input');
cityInput.disabled = false;
}
})
.catch(function (err) {
console.warn('City list unavailable, using text input', err);
setCityMode(citySelect, cityInput, cityFieldName, 'input');
cityInput.disabled = false;
});
});
if (countrySelect.value && data[countrySelect.value]) {
stateSelect.dispatchEvent(new Event('change'));
}
});
}
function bootRegisterLocationDropdowns() {
initRegisterLocationDropdowns().catch(function (err) {
console.error('Register location dropdowns failed to initialize', err);
});
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', bootRegisterLocationDropdowns);
} else {
bootRegisterLocationDropdowns();
}
})();

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -70,12 +70,7 @@
</div> </div>
</div> </div>
</div> </div>
<div class="row mb-3"> @include('partials.register-whatsapp-field')
<label for="phone" class="col-4 col-xl-3 col-form-label">WhatsApp Mobile Number</label>
<div class="col-8 col-xl-9">
<input type="text" class="form-control" id="phone" name="phone" title="Enter valid 10-digit Mobile Number" pattern="[6-9]{1}[0-9]{9}" required>
</div>
</div>
<div class="row mb-3"> <div class="row mb-3">
<label for="alternate_phone" class="col-4 col-xl-3 col-form-label">Alternate Contact Number</label> <label for="alternate_phone" class="col-4 col-xl-3 col-form-label">Alternate Contact Number</label>
<div class="col-8 col-xl-9"> <div class="col-8 col-xl-9">
@ -88,55 +83,8 @@
<input type="email" class="form-control" id="email" name="email" required> <input type="email" class="form-control" id="email" name="email" required>
</div> </div>
</div> </div>
<div class="row mb-3"> @include('partials.register-location-fields')
<label for="city" class="col-4 col-xl-3 col-form-label">City</label>
<div class="col-8 col-xl-9">
<input type="text" class="form-control" id="city" name="city" required>
</div>
</div>
<div class="row mb-3">
<label for="state" class="col-4 col-xl-3 col-form-label">State</label>
<div class="col-8 col-xl-9">
<select name="state" id="state" class="form-control" required>
<option value="Andhra Pradesh">Andhra Pradesh</option>
<option value="Andaman and Nicobar Islands">Andaman and Nicobar Islands</option>
<option value="Arunachal Pradesh">Arunachal Pradesh</option>
<option value="Assam">Assam</option>
<option value="Bihar">Bihar</option>
<option value="Chandigarh">Chandigarh</option>
<option value="Chhattisgarh">Chhattisgarh</option>
<option value="Dadar and Nagar Haveli">Dadar and Nagar Haveli</option>
<option value="Daman and Diu">Daman and Diu</option>
<option value="Delhi">Delhi</option>
<option value="Lakshadweep">Lakshadweep</option>
<option value="Puducherry">Puducherry</option>
<option value="Goa">Goa</option>
<option value="Gujarat">Gujarat</option>
<option value="Haryana">Haryana</option>
<option value="Himachal Pradesh">Himachal Pradesh</option>
<option value="Jammu and Kashmir">Jammu and Kashmir</option>
<option value="Jharkhand">Jharkhand</option>
<option value="Karnataka">Karnataka</option>
<option value="Kerala">Kerala</option>
<option value="Madhya Pradesh">Madhya Pradesh</option>
<option value="Maharashtra">Maharashtra</option>
<option value="Manipur">Manipur</option>
<option value="Meghalaya">Meghalaya</option>
<option value="Mizoram">Mizoram</option>
<option value="Nagaland">Nagaland</option>
<option value="Odisha">Odisha</option>
<option value="Punjab">Punjab</option>
<option value="Rajasthan">Rajasthan</option>
<option value="Sikkim">Sikkim</option>
<option value="Tamil Nadu">Tamil Nadu</option>
<option value="Telangana">Telangana</option>
<option value="Tripura">Tripura</option>
<option value="Uttar Pradesh">Uttar Pradesh</option>
<option value="Uttarakhand">Uttarakhand</option>
<option value="West Bengal">West Bengal</option>
</select>
</div>
</div>
<div class="row mb-3"> <div class="row mb-3">
<label for="highlight_qualification" class="col-4 col-xl-3 col-form-label">Highest Qualification</label> <label for="highlight_qualification" class="col-4 col-xl-3 col-form-label">Highest Qualification</label>
<div class="col-8 col-xl-9"> <div class="col-8 col-xl-9">
@ -236,6 +184,8 @@
<!-- end page --> <!-- end page -->
@include('layouts.shared/footer-script') @include('layouts.shared/footer-script')
@include('partials.register-location-scripts')
<script src="{{asset('assets/libs/flatpickr/flatpickr.min.js')}}"></script> <script src="{{asset('assets/libs/flatpickr/flatpickr.min.js')}}"></script>
<script type="text/javascript"> <script type="text/javascript">
$('.datepicker').flatpickr(); $('.datepicker').flatpickr();

View File

@ -71,12 +71,7 @@
</div> </div>
</div> </div>
</div> </div>
<div class="row mb-3"> @include('partials.register-whatsapp-field')
<label for="phone" class="col-4 col-xl-3 col-form-label">WhatsApp Mobile Number</label>
<div class="col-8 col-xl-9">
<input type="text" class="form-control" id="phone" name="phone" title="Enter valid 10-digit Mobile Number" pattern="[6-9]{1}[0-9]{9}" required>
</div>
</div>
<div class="row mb-3"> <div class="row mb-3">
<label for="alternate_phone" class="col-4 col-xl-3 col-form-label">Alternate Contact Number</label> <label for="alternate_phone" class="col-4 col-xl-3 col-form-label">Alternate Contact Number</label>
<div class="col-8 col-xl-9"> <div class="col-8 col-xl-9">
@ -89,55 +84,8 @@
<input type="email" class="form-control" id="email" name="email" required> <input type="email" class="form-control" id="email" name="email" required>
</div> </div>
</div> </div>
<div class="row mb-3"> @include('partials.register-location-fields')
<label for="city" class="col-4 col-xl-3 col-form-label">City</label>
<div class="col-8 col-xl-9">
<input type="text" class="form-control" id="city" name="city" required>
</div>
</div>
<div class="row mb-3">
<label for="state" class="col-4 col-xl-3 col-form-label">State</label>
<div class="col-8 col-xl-9">
<select name="state" id="state" class="form-control" required>
<option value="Andhra Pradesh">Andhra Pradesh</option>
<option value="Andaman and Nicobar Islands">Andaman and Nicobar Islands</option>
<option value="Arunachal Pradesh">Arunachal Pradesh</option>
<option value="Assam">Assam</option>
<option value="Bihar">Bihar</option>
<option value="Chandigarh">Chandigarh</option>
<option value="Chhattisgarh">Chhattisgarh</option>
<option value="Dadar and Nagar Haveli">Dadar and Nagar Haveli</option>
<option value="Daman and Diu">Daman and Diu</option>
<option value="Delhi">Delhi</option>
<option value="Lakshadweep">Lakshadweep</option>
<option value="Puducherry">Puducherry</option>
<option value="Goa">Goa</option>
<option value="Gujarat">Gujarat</option>
<option value="Haryana">Haryana</option>
<option value="Himachal Pradesh">Himachal Pradesh</option>
<option value="Jammu and Kashmir">Jammu and Kashmir</option>
<option value="Jharkhand">Jharkhand</option>
<option value="Karnataka">Karnataka</option>
<option value="Kerala">Kerala</option>
<option value="Madhya Pradesh">Madhya Pradesh</option>
<option value="Maharashtra">Maharashtra</option>
<option value="Manipur">Manipur</option>
<option value="Meghalaya">Meghalaya</option>
<option value="Mizoram">Mizoram</option>
<option value="Nagaland">Nagaland</option>
<option value="Odisha">Odisha</option>
<option value="Punjab">Punjab</option>
<option value="Rajasthan">Rajasthan</option>
<option value="Sikkim">Sikkim</option>
<option value="Tamil Nadu">Tamil Nadu</option>
<option value="Telangana">Telangana</option>
<option value="Tripura">Tripura</option>
<option value="Uttar Pradesh">Uttar Pradesh</option>
<option value="Uttarakhand">Uttarakhand</option>
<option value="West Bengal">West Bengal</option>
</select>
</div>
</div>
<div class="row mb-3"> <div class="row mb-3">
<label for="highlight_qualification" class="col-4 col-xl-3 col-form-label">Qualification</label> <label for="highlight_qualification" class="col-4 col-xl-3 col-form-label">Qualification</label>
<div class="col-8 col-xl-9"> <div class="col-8 col-xl-9">
@ -242,6 +190,8 @@
<!-- end page --> <!-- end page -->
@include('layouts.shared/footer-script') @include('layouts.shared/footer-script')
@include('partials.register-location-scripts')
<script src="{{asset('assets/libs/flatpickr/flatpickr.min.js')}}"></script> <script src="{{asset('assets/libs/flatpickr/flatpickr.min.js')}}"></script>
<script type="text/javascript"> <script type="text/javascript">
const FLATPICKR_CUSTOM_YEAR_SELECT = 'flatpickr-custom-year-select'; const FLATPICKR_CUSTOM_YEAR_SELECT = 'flatpickr-custom-year-select';

View File

@ -71,12 +71,7 @@
</div> </div>
</div> </div>
</div> </div>
<div class="row mb-3"> @include('partials.register-whatsapp-field')
<label for="phone" class="col-4 col-xl-3 col-form-label">WhatsApp Mobile Number</label>
<div class="col-8 col-xl-9">
<input type="text" class="form-control" id="phone" name="phone" title="Enter valid 10-digit Mobile Number" pattern="[6-9]{1}[0-9]{9}" required>
</div>
</div>
<div class="row mb-3"> <div class="row mb-3">
<label for="alternate_phone" class="col-4 col-xl-3 col-form-label">Alternate Contact Number</label> <label for="alternate_phone" class="col-4 col-xl-3 col-form-label">Alternate Contact Number</label>
<div class="col-8 col-xl-9"> <div class="col-8 col-xl-9">
@ -89,55 +84,8 @@
<input type="email" class="form-control" id="email" name="email" required> <input type="email" class="form-control" id="email" name="email" required>
</div> </div>
</div> </div>
<div class="row mb-3"> @include('partials.register-location-fields')
<label for="city" class="col-4 col-xl-3 col-form-label">City</label>
<div class="col-8 col-xl-9">
<input type="text" class="form-control" id="city" name="city" required>
</div>
</div>
<div class="row mb-3">
<label for="state" class="col-4 col-xl-3 col-form-label">State</label>
<div class="col-8 col-xl-9">
<select name="state" id="state" class="form-control" required>
<option value="Andhra Pradesh">Andhra Pradesh</option>
<option value="Andaman and Nicobar Islands">Andaman and Nicobar Islands</option>
<option value="Arunachal Pradesh">Arunachal Pradesh</option>
<option value="Assam">Assam</option>
<option value="Bihar">Bihar</option>
<option value="Chandigarh">Chandigarh</option>
<option value="Chhattisgarh">Chhattisgarh</option>
<option value="Dadar and Nagar Haveli">Dadar and Nagar Haveli</option>
<option value="Daman and Diu">Daman and Diu</option>
<option value="Delhi">Delhi</option>
<option value="Lakshadweep">Lakshadweep</option>
<option value="Puducherry">Puducherry</option>
<option value="Goa">Goa</option>
<option value="Gujarat">Gujarat</option>
<option value="Haryana">Haryana</option>
<option value="Himachal Pradesh">Himachal Pradesh</option>
<option value="Jammu and Kashmir">Jammu and Kashmir</option>
<option value="Jharkhand">Jharkhand</option>
<option value="Karnataka">Karnataka</option>
<option value="Kerala">Kerala</option>
<option value="Madhya Pradesh">Madhya Pradesh</option>
<option value="Maharashtra">Maharashtra</option>
<option value="Manipur">Manipur</option>
<option value="Meghalaya">Meghalaya</option>
<option value="Mizoram">Mizoram</option>
<option value="Nagaland">Nagaland</option>
<option value="Odisha">Odisha</option>
<option value="Punjab">Punjab</option>
<option value="Rajasthan">Rajasthan</option>
<option value="Sikkim">Sikkim</option>
<option value="Tamil Nadu">Tamil Nadu</option>
<option value="Telangana">Telangana</option>
<option value="Tripura">Tripura</option>
<option value="Uttar Pradesh">Uttar Pradesh</option>
<option value="Uttarakhand">Uttarakhand</option>
<option value="West Bengal">West Bengal</option>
</select>
</div>
</div>
<div class="row mb-3"> <div class="row mb-3">
<label for="highlight_qualification" class="col-4 col-xl-3 col-form-label">Qualification</label> <label for="highlight_qualification" class="col-4 col-xl-3 col-form-label">Qualification</label>
<div class="col-8 col-xl-9"> <div class="col-8 col-xl-9">
@ -242,6 +190,8 @@
<!-- end page --> <!-- end page -->
@include('layouts.shared/footer-script') @include('layouts.shared/footer-script')
@include('partials.register-location-scripts')
<script src="{{asset('assets/libs/flatpickr/flatpickr.min.js')}}"></script> <script src="{{asset('assets/libs/flatpickr/flatpickr.min.js')}}"></script>
<script type="text/javascript"> <script type="text/javascript">
$('.datepicker').flatpickr(); $('.datepicker').flatpickr();

View File

@ -71,12 +71,7 @@
</div> </div>
</div> </div>
</div> </div>
<div class="row mb-3"> @include('partials.register-whatsapp-field')
<label for="phone" class="col-4 col-xl-3 col-form-label">WhatsApp Mobile Number</label>
<div class="col-8 col-xl-9">
<input type="text" class="form-control" id="phone" name="phone" title="Enter valid 10-digit Mobile Number" pattern="[6-9]{1}[0-9]{9}" required>
</div>
</div>
<div class="row mb-3"> <div class="row mb-3">
<label for="alternate_phone" class="col-4 col-xl-3 col-form-label">Alternate Contact Number</label> <label for="alternate_phone" class="col-4 col-xl-3 col-form-label">Alternate Contact Number</label>
<div class="col-8 col-xl-9"> <div class="col-8 col-xl-9">
@ -89,55 +84,8 @@
<input type="email" class="form-control" id="email" name="email" required> <input type="email" class="form-control" id="email" name="email" required>
</div> </div>
</div> </div>
<div class="row mb-3"> @include('partials.register-location-fields')
<label for="city" class="col-4 col-xl-3 col-form-label">City</label>
<div class="col-8 col-xl-9">
<input type="text" class="form-control" id="city" name="city" required>
</div>
</div>
<div class="row mb-3">
<label for="state" class="col-4 col-xl-3 col-form-label">State</label>
<div class="col-8 col-xl-9">
<select name="state" id="state" class="form-control" required>
<option value="Andhra Pradesh">Andhra Pradesh</option>
<option value="Andaman and Nicobar Islands">Andaman and Nicobar Islands</option>
<option value="Arunachal Pradesh">Arunachal Pradesh</option>
<option value="Assam">Assam</option>
<option value="Bihar">Bihar</option>
<option value="Chandigarh">Chandigarh</option>
<option value="Chhattisgarh">Chhattisgarh</option>
<option value="Dadar and Nagar Haveli">Dadar and Nagar Haveli</option>
<option value="Daman and Diu">Daman and Diu</option>
<option value="Delhi">Delhi</option>
<option value="Lakshadweep">Lakshadweep</option>
<option value="Puducherry">Puducherry</option>
<option value="Goa">Goa</option>
<option value="Gujarat">Gujarat</option>
<option value="Haryana">Haryana</option>
<option value="Himachal Pradesh">Himachal Pradesh</option>
<option value="Jammu and Kashmir">Jammu and Kashmir</option>
<option value="Jharkhand">Jharkhand</option>
<option value="Karnataka">Karnataka</option>
<option value="Kerala">Kerala</option>
<option value="Madhya Pradesh">Madhya Pradesh</option>
<option value="Maharashtra">Maharashtra</option>
<option value="Manipur">Manipur</option>
<option value="Meghalaya">Meghalaya</option>
<option value="Mizoram">Mizoram</option>
<option value="Nagaland">Nagaland</option>
<option value="Odisha">Odisha</option>
<option value="Punjab">Punjab</option>
<option value="Rajasthan">Rajasthan</option>
<option value="Sikkim">Sikkim</option>
<option value="Tamil Nadu">Tamil Nadu</option>
<option value="Telangana">Telangana</option>
<option value="Tripura">Tripura</option>
<option value="Uttar Pradesh">Uttar Pradesh</option>
<option value="Uttarakhand">Uttarakhand</option>
<option value="West Bengal">West Bengal</option>
</select>
</div>
</div>
<div class="row mb-3"> <div class="row mb-3">
<label for="highlight_qualification" class="col-4 col-xl-3 col-form-label">Qualification</label> <label for="highlight_qualification" class="col-4 col-xl-3 col-form-label">Qualification</label>
<div class="col-8 col-xl-9"> <div class="col-8 col-xl-9">
@ -242,6 +190,8 @@
<!-- end page --> <!-- end page -->
@include('layouts.shared/footer-script') @include('layouts.shared/footer-script')
@include('partials.register-location-scripts')
<script src="{{asset('assets/libs/flatpickr/flatpickr.min.js')}}"></script> <script src="{{asset('assets/libs/flatpickr/flatpickr.min.js')}}"></script>
<script type="text/javascript"> <script type="text/javascript">
$('.datepicker').flatpickr(); $('.datepicker').flatpickr();

View File

@ -71,12 +71,7 @@
</div> </div>
</div> </div>
</div> </div>
<div class="row mb-3"> @include('partials.register-whatsapp-field')
<label for="phone" class="col-4 col-xl-3 col-form-label">WhatsApp Mobile Number</label>
<div class="col-8 col-xl-9">
<input type="text" class="form-control" id="phone" name="phone" title="Enter valid 10-digit Mobile Number" pattern="[6-9]{1}[0-9]{9}" required>
</div>
</div>
<div class="row mb-3"> <div class="row mb-3">
<label for="alternate_phone" class="col-4 col-xl-3 col-form-label">Alternate Contact Number</label> <label for="alternate_phone" class="col-4 col-xl-3 col-form-label">Alternate Contact Number</label>
<div class="col-8 col-xl-9"> <div class="col-8 col-xl-9">
@ -89,55 +84,8 @@
<input type="email" class="form-control" id="email" name="email" required> <input type="email" class="form-control" id="email" name="email" required>
</div> </div>
</div> </div>
<div class="row mb-3"> @include('partials.register-location-fields')
<label for="city" class="col-4 col-xl-3 col-form-label">City</label>
<div class="col-8 col-xl-9">
<input type="text" class="form-control" id="city" name="city" required>
</div>
</div>
<div class="row mb-3">
<label for="state" class="col-4 col-xl-3 col-form-label">State</label>
<div class="col-8 col-xl-9">
<select name="state" id="state" class="form-control" required>
<option value="Andhra Pradesh">Andhra Pradesh</option>
<option value="Andaman and Nicobar Islands">Andaman and Nicobar Islands</option>
<option value="Arunachal Pradesh">Arunachal Pradesh</option>
<option value="Assam">Assam</option>
<option value="Bihar">Bihar</option>
<option value="Chandigarh">Chandigarh</option>
<option value="Chhattisgarh">Chhattisgarh</option>
<option value="Dadar and Nagar Haveli">Dadar and Nagar Haveli</option>
<option value="Daman and Diu">Daman and Diu</option>
<option value="Delhi">Delhi</option>
<option value="Lakshadweep">Lakshadweep</option>
<option value="Puducherry">Puducherry</option>
<option value="Goa">Goa</option>
<option value="Gujarat">Gujarat</option>
<option value="Haryana">Haryana</option>
<option value="Himachal Pradesh">Himachal Pradesh</option>
<option value="Jammu and Kashmir">Jammu and Kashmir</option>
<option value="Jharkhand">Jharkhand</option>
<option value="Karnataka">Karnataka</option>
<option value="Kerala">Kerala</option>
<option value="Madhya Pradesh">Madhya Pradesh</option>
<option value="Maharashtra">Maharashtra</option>
<option value="Manipur">Manipur</option>
<option value="Meghalaya">Meghalaya</option>
<option value="Mizoram">Mizoram</option>
<option value="Nagaland">Nagaland</option>
<option value="Odisha">Odisha</option>
<option value="Punjab">Punjab</option>
<option value="Rajasthan">Rajasthan</option>
<option value="Sikkim">Sikkim</option>
<option value="Tamil Nadu">Tamil Nadu</option>
<option value="Telangana">Telangana</option>
<option value="Tripura">Tripura</option>
<option value="Uttar Pradesh">Uttar Pradesh</option>
<option value="Uttarakhand">Uttarakhand</option>
<option value="West Bengal">West Bengal</option>
</select>
</div>
</div>
<div class="row mb-3"> <div class="row mb-3">
<label for="highlight_qualification" class="col-4 col-xl-3 col-form-label">Qualification</label> <label for="highlight_qualification" class="col-4 col-xl-3 col-form-label">Qualification</label>
<div class="col-8 col-xl-9"> <div class="col-8 col-xl-9">
@ -258,6 +206,8 @@
<!-- end page --> <!-- end page -->
@include('layouts.shared/footer-script') @include('layouts.shared/footer-script')
@include('partials.register-location-scripts')
<script src="{{asset('assets/libs/flatpickr/flatpickr.min.js')}}"></script> <script src="{{asset('assets/libs/flatpickr/flatpickr.min.js')}}"></script>
<script type="text/javascript"> <script type="text/javascript">
$('.datepicker').flatpickr(); $('.datepicker').flatpickr();

View File

@ -185,9 +185,17 @@
$('#field-header_params').html('') $('#field-header_params').html('')
$('#field-body_params').html('') $('#field-body_params').html('')
$('#field-button_params').html('') $('#field-button_params').html('')
$('#field-button_cta').html('')
console.log(template_data) console.log(template_data)
if(template_data) { if(template_data) {
$('#field-template_body').html(template_data.template_body) $('#field-template_body').html(template_data.template_body)
if(template_data.button_url || template_data.button_label) {
$('#field-button_cta').html(
'<div class="col-12 mb-2"><strong>Email button</strong></div>'
+ '<div class="col-12 mb-2 text-muted small">URL: ' + (template_data.button_url || '-') + '</div>'
+ '<div class="col-12 mb-2 text-muted small">Label: ' + (template_data.button_label || 'Click here') + '</div>'
)
}
if(template_data.header_params != null) if(template_data.header_params != null)
for(let p of template_data.header_params.split('||') ) { for(let p of template_data.header_params.split('||') ) {
$('#field-header_params').append('<div class="col-6 mb-2">'+p+'</div><div class="col-6 mb-2"><input type="text" name="header_params[]" class="form-control" value="'+p+'" required> </div>') $('#field-header_params').append('<div class="col-6 mb-2">'+p+'</div><div class="col-6 mb-2"><input type="text" name="header_params[]" class="form-control" value="'+p+'" required> </div>')

View File

@ -176,9 +176,17 @@
$('#field-header_params').html('') $('#field-header_params').html('')
$('#field-body_params').html('') $('#field-body_params').html('')
$('#field-button_params').html('') $('#field-button_params').html('')
$('#field-button_cta').html('')
console.log(template_data) console.log(template_data)
if(template_data) { if(template_data) {
$('#field-template_body').html(template_data.template_body) $('#field-template_body').html(template_data.template_body)
if(template_data.button_url || template_data.button_label) {
$('#field-button_cta').html(
'<div class="col-12 mb-2"><strong>Email button</strong></div>'
+ '<div class="col-12 mb-2 text-muted small">URL: ' + (template_data.button_url || '-') + '</div>'
+ '<div class="col-12 mb-2 text-muted small">Label: ' + (template_data.button_label || 'Click here') + '</div>'
)
}
if(template_data.header_params != null) if(template_data.header_params != null)
for(let p of template_data.header_params.split('||') ) { for(let p of template_data.header_params.split('||') ) {
$('#field-header_params').append('<div class="col-6 mb-2">'+p+'</div><div class="col-6 mb-2"><input type="text" name="header_params[]" class="form-control" value="'+p+'" required> </div>') $('#field-header_params').append('<div class="col-6 mb-2">'+p+'</div><div class="col-6 mb-2"><input type="text" name="header_params[]" class="form-control" value="'+p+'" required> </div>')

View File

@ -0,0 +1,37 @@
@php
$showRequiredAsterisk = $showRequiredAsterisk ?? false;
$defaultCountry = $defaultCountry ?? 'India';
$cityField = $cityField ?? 'city';
$cityLabel = $cityLabel ?? 'City';
$persistCountryState = $persistCountryState ?? true;
$requiredMark = $showRequiredAsterisk ? ' <span class="text-danger">*</span>' : '';
$countryName = $persistCountryState ? 'country' : '';
$stateName = $persistCountryState ? 'state' : '';
@endphp
<div class="register-location-fields" data-city-field="{{ $cityField }}" data-default-country="{{ $defaultCountry }}">
<div class="row mb-3">
<label for="country" class="col-4 col-xl-3 col-form-label">Country{!! $requiredMark !!}</label>
<div class="col-8 col-xl-9">
<select @if($countryName) name="{{ $countryName }}" @endif id="country" class="form-control register-location-country" required>
<option value="">-- Select Country --</option>
</select>
</div>
</div>
<div class="row mb-3">
<label for="state" class="col-4 col-xl-3 col-form-label">State{!! $requiredMark !!}</label>
<div class="col-8 col-xl-9">
<select @if($stateName) name="{{ $stateName }}" @endif id="state" class="form-control register-location-state" required disabled>
<option value="">-- Select State --</option>
</select>
</div>
</div>
<div class="row mb-3 register-location-city-row">
<label for="city" class="col-4 col-xl-3 col-form-label">{{ $cityLabel }}{!! $requiredMark !!}</label>
<div class="col-8 col-xl-9">
<select id="city" class="form-control register-location-city-select" required disabled style="display: none;">
<option value="">-- Select City --</option>
</select>
<input type="text" class="form-control register-location-city-input" id="city_text" name="{{ $cityField }}" placeholder="Enter city" required disabled>
</div>
</div>
</div>

View File

@ -0,0 +1,27 @@
@php
$registerLocationCountries = [];
foreach ([
resource_path('data/countriesAndStates.json'),
public_path('assets/data/countriesAndStates.json'),
storage_path('app/geo/countriesAndStates.json'),
public_path('data/countriesAndStates.json'),
] as $countriesPath) {
if (is_readable($countriesPath)) {
$decoded = json_decode(file_get_contents($countriesPath), true);
if (is_array($decoded) && count($decoded) > 0 && array_keys($decoded) !== range(0, count($decoded) - 1)) {
$registerLocationCountries = $decoded;
break;
}
}
}
@endphp
<script src="{{ asset('assets/js/register-location-countries-data.js') }}"></script>
@if(count($registerLocationCountries) > 0)
<script>
window.REGISTER_LOCATION_COUNTRIES = @json($registerLocationCountries);
</script>
@endif
<script>
window.REGISTER_LOCATION_CITIES_URL = @json(url('/geo/cities'));
</script>
<script src="{{ asset('assets/js/register-location-dropdowns.js') }}"></script>

View File

@ -0,0 +1,13 @@
@if(($communication_mode ?? 'whatsapp') !== 'email')
<div class="row mb-3">
<label for="phone" class="col-4 col-xl-3 col-form-label">
WhatsApp Mobile Number
@if(!empty($showRequiredStar))
<span class="text-danger">*</span>
@endif
</label>
<div class="col-8 col-xl-9">
<input type="text" class="form-control" id="phone" name="phone" title="Enter valid 10-digit Mobile Number" pattern="{{ $phonePattern ?? '[6-9]{1}[0-9]{9}' }}" required>
</div>
</div>
@endif

View File

@ -68,15 +68,12 @@
required> required>
</div> </div>
</div> </div>
<div class="row mb-3"> @include('partials.register-location-fields', [
<label for="city_town" class="col-4 col-xl-3 col-form-label"><span 'showRequiredAsterisk' => true,
class="text-danger">*</span> City / Town </label> 'cityField' => 'city_town',
<div class="col-8 col-xl-9"> 'cityLabel' => 'City / Town',
<input type="city_town" class="form-control" id="city_town" name="city_town" 'persistCountryState' => false,
value="{{ isset($userdata->city_town) ? $userdata->city_town : '' }}" ])
required>
</div>
</div>
<div class="row mb-3"> <div class="row mb-3">
<label for="qualification" class="col-4 col-xl-3 col-form-label"><span <label for="qualification" class="col-4 col-xl-3 col-form-label"><span
@ -493,6 +490,7 @@
<!-- end page --> <!-- end page -->
@include('layouts.shared/footer-script') @include('layouts.shared/footer-script')
@include('partials.register-location-scripts')
<script src="{{ asset('assets/libs/flatpickr/flatpickr.min.js') }}"></script> <script src="{{ asset('assets/libs/flatpickr/flatpickr.min.js') }}"></script>
<script type="text/javascript"> <script type="text/javascript">
$('.datepicker').flatpickr(); $('.datepicker').flatpickr();

View File

@ -70,12 +70,7 @@
</div> </div>
</div> </div>
</div> </div>
<div class="row mb-3"> @include('partials.register-whatsapp-field')
<label for="phone" class="col-4 col-xl-3 col-form-label">WhatsApp Mobile Number</label>
<div class="col-8 col-xl-9">
<input type="text" class="form-control" id="phone" name="phone" title="Enter valid 10-digit Mobile Number" pattern="[6-9]{1}[0-9]{9}" required>
</div>
</div>
<div class="row mb-3"> <div class="row mb-3">
<label for="alternate_phone" class="col-4 col-xl-3 col-form-label">Alternate Contact Number</label> <label for="alternate_phone" class="col-4 col-xl-3 col-form-label">Alternate Contact Number</label>
<div class="col-8 col-xl-9"> <div class="col-8 col-xl-9">
@ -88,55 +83,8 @@
<input type="email" class="form-control" id="email" name="email" required> <input type="email" class="form-control" id="email" name="email" required>
</div> </div>
</div> </div>
<div class="row mb-3"> @include('partials.register-location-fields')
<label for="city" class="col-4 col-xl-3 col-form-label">City</label>
<div class="col-8 col-xl-9">
<input type="text" class="form-control" id="city" name="city" required>
</div>
</div>
<div class="row mb-3">
<label for="state" class="col-4 col-xl-3 col-form-label">State</label>
<div class="col-8 col-xl-9">
<select name="state" id="state" class="form-control" required>
<option value="Andhra Pradesh">Andhra Pradesh</option>
<option value="Andaman and Nicobar Islands">Andaman and Nicobar Islands</option>
<option value="Arunachal Pradesh">Arunachal Pradesh</option>
<option value="Assam">Assam</option>
<option value="Bihar">Bihar</option>
<option value="Chandigarh">Chandigarh</option>
<option value="Chhattisgarh">Chhattisgarh</option>
<option value="Dadar and Nagar Haveli">Dadar and Nagar Haveli</option>
<option value="Daman and Diu">Daman and Diu</option>
<option value="Delhi">Delhi</option>
<option value="Lakshadweep">Lakshadweep</option>
<option value="Puducherry">Puducherry</option>
<option value="Goa">Goa</option>
<option value="Gujarat">Gujarat</option>
<option value="Haryana">Haryana</option>
<option value="Himachal Pradesh">Himachal Pradesh</option>
<option value="Jammu and Kashmir">Jammu and Kashmir</option>
<option value="Jharkhand">Jharkhand</option>
<option value="Karnataka">Karnataka</option>
<option value="Kerala">Kerala</option>
<option value="Madhya Pradesh">Madhya Pradesh</option>
<option value="Maharashtra">Maharashtra</option>
<option value="Manipur">Manipur</option>
<option value="Meghalaya">Meghalaya</option>
<option value="Mizoram">Mizoram</option>
<option value="Nagaland">Nagaland</option>
<option value="Odisha">Odisha</option>
<option value="Punjab">Punjab</option>
<option value="Rajasthan">Rajasthan</option>
<option value="Sikkim">Sikkim</option>
<option value="Tamil Nadu">Tamil Nadu</option>
<option value="Telangana">Telangana</option>
<option value="Tripura">Tripura</option>
<option value="Uttar Pradesh">Uttar Pradesh</option>
<option value="Uttarakhand">Uttarakhand</option>
<option value="West Bengal">West Bengal</option>
</select>
</div>
</div>
<div class="row mb-3"> <div class="row mb-3">
<label for="highlight_qualification" class="col-4 col-xl-3 col-form-label">Highest Qualification</label> <label for="highlight_qualification" class="col-4 col-xl-3 col-form-label">Highest Qualification</label>
<div class="col-8 col-xl-9"> <div class="col-8 col-xl-9">
@ -247,6 +195,8 @@
<!-- end page --> <!-- end page -->
@include('layouts.shared/footer-script') @include('layouts.shared/footer-script')
@include('partials.register-location-scripts')
<script src="{{asset('assets/libs/flatpickr/flatpickr.min.js')}}"></script> <script src="{{asset('assets/libs/flatpickr/flatpickr.min.js')}}"></script>
<script type="text/javascript"> <script type="text/javascript">
$('.datepicker').flatpickr(); $('.datepicker').flatpickr();

View File

@ -71,12 +71,7 @@
</div> </div>
</div> </div>
</div> </div>
<div class="row mb-3"> @include('partials.register-whatsapp-field')
<label for="phone" class="col-4 col-xl-3 col-form-label">WhatsApp Mobile Number</label>
<div class="col-8 col-xl-9">
<input type="text" class="form-control" id="phone" name="phone" title="Enter valid 10-digit Mobile Number" pattern="[6-9]{1}[0-9]{9}" required>
</div>
</div>
<div class="row mb-3"> <div class="row mb-3">
<label for="alternate_phone" class="col-4 col-xl-3 col-form-label">Alternate Contact Number</label> <label for="alternate_phone" class="col-4 col-xl-3 col-form-label">Alternate Contact Number</label>
<div class="col-8 col-xl-9"> <div class="col-8 col-xl-9">
@ -89,55 +84,8 @@
<input type="email" class="form-control" id="email" name="email" required> <input type="email" class="form-control" id="email" name="email" required>
</div> </div>
</div> </div>
<div class="row mb-3"> @include('partials.register-location-fields')
<label for="city" class="col-4 col-xl-3 col-form-label">City</label>
<div class="col-8 col-xl-9">
<input type="text" class="form-control" id="city" name="city" required>
</div>
</div>
<div class="row mb-3">
<label for="state" class="col-4 col-xl-3 col-form-label">State</label>
<div class="col-8 col-xl-9">
<select name="state" id="state" class="form-control" required>
<option value="Andhra Pradesh">Andhra Pradesh</option>
<option value="Andaman and Nicobar Islands">Andaman and Nicobar Islands</option>
<option value="Arunachal Pradesh">Arunachal Pradesh</option>
<option value="Assam">Assam</option>
<option value="Bihar">Bihar</option>
<option value="Chandigarh">Chandigarh</option>
<option value="Chhattisgarh">Chhattisgarh</option>
<option value="Dadar and Nagar Haveli">Dadar and Nagar Haveli</option>
<option value="Daman and Diu">Daman and Diu</option>
<option value="Delhi">Delhi</option>
<option value="Lakshadweep">Lakshadweep</option>
<option value="Puducherry">Puducherry</option>
<option value="Goa">Goa</option>
<option value="Gujarat">Gujarat</option>
<option value="Haryana">Haryana</option>
<option value="Himachal Pradesh">Himachal Pradesh</option>
<option value="Jammu and Kashmir">Jammu and Kashmir</option>
<option value="Jharkhand">Jharkhand</option>
<option value="Karnataka">Karnataka</option>
<option value="Kerala">Kerala</option>
<option value="Madhya Pradesh">Madhya Pradesh</option>
<option value="Maharashtra">Maharashtra</option>
<option value="Manipur">Manipur</option>
<option value="Meghalaya">Meghalaya</option>
<option value="Mizoram">Mizoram</option>
<option value="Nagaland">Nagaland</option>
<option value="Odisha">Odisha</option>
<option value="Punjab">Punjab</option>
<option value="Rajasthan">Rajasthan</option>
<option value="Sikkim">Sikkim</option>
<option value="Tamil Nadu">Tamil Nadu</option>
<option value="Telangana">Telangana</option>
<option value="Tripura">Tripura</option>
<option value="Uttar Pradesh">Uttar Pradesh</option>
<option value="Uttarakhand">Uttarakhand</option>
<option value="West Bengal">West Bengal</option>
</select>
</div>
</div>
<div class="row mb-3"> <div class="row mb-3">
<label for="highlight_qualification" class="col-4 col-xl-3 col-form-label">Highest Qualification</label> <label for="highlight_qualification" class="col-4 col-xl-3 col-form-label">Highest Qualification</label>
<div class="col-8 col-xl-9"> <div class="col-8 col-xl-9">
@ -254,6 +202,8 @@
<!-- end page --> <!-- end page -->
@include('layouts.shared/footer-script') @include('layouts.shared/footer-script')
@include('partials.register-location-scripts')
<script src="{{asset('assets/libs/flatpickr/flatpickr.min.js')}}"></script> <script src="{{asset('assets/libs/flatpickr/flatpickr.min.js')}}"></script>
<script type="text/javascript"> <script type="text/javascript">
$('.datepicker').flatpickr(); $('.datepicker').flatpickr();

View File

@ -1,5 +1,6 @@
<?php <?php
use App\Http\Controllers\RegisterLocationController;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route; use Illuminate\Support\Facades\Route;
@ -14,6 +15,9 @@ use Illuminate\Support\Facades\Route;
| |
*/ */
Route::get('/geo/countries', [RegisterLocationController::class, 'countries']);
Route::get('/geo/cities', [RegisterLocationController::class, 'cities']);
Route::middleware('auth:api')->get('/user', function (Request $request) { Route::middleware('auth:api')->get('/user', function (Request $request) {
return $request->user(); return $request->user();
}); });

View File

@ -23,6 +23,7 @@ use App\Http\Controllers\FacultyController;
use App\Http\Controllers\SessionController; use App\Http\Controllers\SessionController;
use App\Http\Controllers\SessionagendaController; use App\Http\Controllers\SessionagendaController;
use App\Http\Controllers\MicrositeController; use App\Http\Controllers\MicrositeController;
use App\Http\Controllers\RegisterLocationController;
use App\Http\Controllers\SessionagendalibController; use App\Http\Controllers\SessionagendalibController;
use App\Http\Controllers\MsgtemplateController; use App\Http\Controllers\MsgtemplateController;
@ -70,6 +71,10 @@ use App\Http\Controllers\CommentController;
| |
*/ */
// Public geo data for registration forms (must stay above catch-all routes).
Route::get('/geo/countries', [RegisterLocationController::class, 'countries']);
Route::get('/geo/cities', [RegisterLocationController::class, 'cities']);
Route::get('/', [DashboardController::class, 'index'])->name('home'); Route::get('/', [DashboardController::class, 'index'])->name('home');
Route::get('/index', [DashboardController::class, 'index'])->name('home'); Route::get('/index', [DashboardController::class, 'index'])->name('home');
Route::get('/login', [LoginController::class, 'index'])->name('login'); Route::get('/login', [LoginController::class, 'index'])->name('login');

View File

@ -1,44 +0,0 @@
<?php
require_once __DIR__ . '/includes/data.php';
$pageTitle = 'Achievements | CREST';
$metaDescription = 'See CREST milestones: lives impacted, doctors trained, studies completed, and partnerships across India.';
include __DIR__ . '/includes/site-header.php';
?>
<main>
<section class="py-5">
<div class="container">
<p class="text-uppercase text-success fw-bold small mb-1">Achievements</p>
<h2 class="fw-bold mb-4">Milestones powered by data and collaboration</h2>
<div class="row row-cols-2 row-cols-md-4 g-3">
<div class="col">
<div class="stat-tile text-center p-3 rounded-4">
<div class="fw-bold">1Mn+</div>
<div class="text-muted small">Lives touched</div>
</div>
</div>
<div class="col">
<div class="stat-tile text-center p-3 rounded-4">
<div class="fw-bold">5k+</div>
<div class="text-muted small">Doctors trained</div>
</div>
</div>
<div class="col">
<div class="stat-tile text-center p-3 rounded-4">
<div class="fw-bold">500+</div>
<div class="text-muted small">Medical schools</div>
</div>
</div>
<div class="col">
<div class="stat-tile text-center p-3 rounded-4">
<div class="fw-bold">300+</div>
<div class="text-muted small">Research studies</div>
</div>
</div>
</div>
<p class="text-muted mt-3">These numbers reflect multi-year partnerships, field programs, and training cohorts across India.</p>
</div>
</section>
</main>
<?php include __DIR__ . '/includes/site-footer.php'; ?>

View File

@ -1,112 +0,0 @@
<?php
require_once __DIR__ . '/../includes/auth.php';
require_login();
$error = '';
$success = '';
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$email = trim($_POST['email'] ?? '');
$password = trim($_POST['password'] ?? '');
if ($email === '' || $password === '') {
$error = 'Email and password are required.';
} elseif (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
$error = 'Please enter a valid email.';
} else {
try {
create_admin($email, $password);
$success = 'Admin added successfully.';
} catch (Throwable $e) {
$error = 'Could not add admin (maybe email already exists).';
}
}
}
$pdo = db();
$admins = $pdo->query("SELECT email, created_at FROM admins ORDER BY created_at DESC");
$admins = is_array($admins) ? $admins : [];
$assetPathPrefix = '../';
$pageTitle = 'Admins';
$currentPage = '';
$extraStyles = <<<CSS
<style>
body { background: #f6faf7; }
.admin-shell { padding: 40px 0; }
.table { width: 100%; border-collapse: collapse; margin-top: 20px; }
.table th, .table td { text-align: left; padding: 12px 10px; border-bottom: 1px solid #e1ede7; }
.table th { color: #0f4333; }
form input { width: 100%; padding: 12px 14px; border-radius: 10px; border: 1px solid #d8e7e0; font-size: 15px; margin-top: 8px; }
form label { font-weight: 700; color: #0f4333; display: block; margin-top: 12px; }
</style>
CSS;
require __DIR__ . '/../includes/admin-header.php';
?>
<main class="admin-shell">
<div class="container">
<div class="topbar" style="display:flex; justify-content:space-between; align-items:center; margin-bottom:16px;">
<div>
<p class="eyebrow">Admins</p>
<h2>Manage administrator accounts</h2>
</div>
</div>
<div class="admin-nav">
<a href="/admin/tutorials.php">Tutorials</a>
<a href="/admin/sessions.php">Upcoming Sessions</a>
<a href="/admin/contacts.php">Contact Entries</a>
<a href="/admin/newsletter.php">Newsletter</a>
<a href="/admin/admins.php">Admins</a>
<a href="/admin/logout.php">Logout (<?php echo htmlspecialchars(current_admin_email() ?? ''); ?>)</a>
</div>
<?php if ($success): ?>
<div class="alert good"><?php echo htmlspecialchars($success); ?></div>
<?php endif; ?>
<?php if ($error): ?>
<div class="alert bad"><?php echo htmlspecialchars($error); ?></div>
<?php endif; ?>
<div class="card">
<h3>Add Admin</h3>
<form method="post">
<label for="email">Email</label>
<input type="email" id="email" name="email" required placeholder="admin@example.com">
<label for="password">Password</label>
<input type="password" id="password" name="password" required placeholder="Choose a secure password">
<div style="margin-top:16px;">
<button type="submit" class="btn primary">Add admin</button>
</div>
</form>
</div>
<div class="card" style="margin-top:20px;">
<h3>Existing Admins</h3>
<?php if (empty($admins)): ?>
<p class="body muted">No admins found.</p>
<?php else: ?>
<table class="table">
<thead>
<tr>
<th>Email</th>
<th>Created</th>
</tr>
</thead>
<tbody>
<?php foreach ($admins as $admin): ?>
<tr>
<td><?php echo htmlspecialchars($admin['email']); ?></td>
<td><?php echo htmlspecialchars($admin['created_at']); ?></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<?php endif; ?>
</div>
</div>
</main>
<?php require __DIR__ . '/../includes/admin-footer.php'; ?>

View File

@ -1,91 +0,0 @@
<?php
require_once __DIR__ . '/../includes/auth.php';
require_login();
$contacts = get_contacts();
$isExport = isset($_GET['export']);
if ($isExport) {
header('Content-Type: text/csv');
header('Content-Disposition: attachment; filename="contacts.csv"');
$out = fopen('php://output', 'w');
fputcsv($out, ['Name', 'Email', 'Organization', 'Message', 'Received']);
foreach ($contacts as $c) {
fputcsv($out, [
$c['name'] ?? '',
$c['email'] ?? '',
$c['organization'] ?? '',
$c['message'] ?? '',
$c['created_at'] ?? '',
]);
}
fclose($out);
exit;
}
$assetPathPrefix = '../';
$pageTitle = 'Contact Entries';
$currentPage = 'contact';
$extraStyles = <<<CSS
<style>
body { background: #f6faf7; }
.admin-shell { padding: 40px 0; }
.table { width: 100%; border-collapse: collapse; margin-top: 20px; }
.table th, .table td { text-align: left; padding: 12px 10px; border-bottom: 1px solid #e1ede7; vertical-align: top; }
.table th { color: #0f4333; }
</style>
CSS;
require __DIR__ . '/../includes/admin-header.php';
?>
<main class="admin-shell">
<div class="container">
<div class="topbar" style="display:flex; justify-content:space-between; align-items:center; margin-bottom:16px;">
<div>
<p class="eyebrow">Contact Entries</p>
<h2>Messages from the contact form</h2>
</div>
<div class="btn ghost" style="pointer-events:none;">Read-only</div>
</div>
<div class="admin-nav">
<a href="/admin/tutorials.php">Tutorials</a>
<a href="/admin/sessions.php">Upcoming Sessions</a>
<a href="/admin/contacts.php">Contact Entries</a>
<a href="/admin/newsletter.php">Newsletter</a>
<a href="/admin/admins.php">Admins</a>
<a href="/admin/logout.php">Logout (<?php echo htmlspecialchars(current_admin_email() ?? ''); ?>)</a>
</div>
<div style="margin:10px 0;">
<a class="btn outline small" href="?export=1">Export CSV</a>
</div>
<?php if (empty($contacts)): ?>
<p class="body muted">No messages yet.</p>
<?php else: ?>
<table class="table">
<thead>
<tr>
<th>Name</th>
<th>Email</th>
<th>Organization</th>
<th>Message</th>
<th>Received</th>
</tr>
</thead>
<tbody>
<?php foreach ($contacts as $contact): ?>
<tr>
<td><?php echo htmlspecialchars($contact['name']); ?></td>
<td><?php echo htmlspecialchars($contact['email']); ?></td>
<td><?php echo htmlspecialchars($contact['organization'] ?? ''); ?></td>
<td><?php echo nl2br(htmlspecialchars($contact['message'])); ?></td>
<td><?php echo htmlspecialchars($contact['created_at']); ?></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<?php endif; ?>
</div>
</main>
<?php require __DIR__ . '/../includes/admin-footer.php'; ?>

View File

@ -1,47 +0,0 @@
<?php
require_once __DIR__ . '/../includes/auth.php';
$error = '';
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$email = trim($_POST['email'] ?? '');
$password = trim($_POST['password'] ?? '');
if ($email === '' || $password === '') {
$error = 'Email and password are required.';
} elseif (attempt_login($email, $password)) {
header('Location: /admin/resources.php');
exit;
} else {
$error = 'Invalid credentials.';
}
}
$pageTitle = 'Admin Login';
$currentPage = '';
$assetPathPrefix = '../';
require __DIR__ . '/../includes/admin-header.php';
?>
<main class="section">
<div class="container" style="max-width:480px;">
<div class="card">
<h2>Admin Login</h2>
<?php if ($error): ?>
<div class="alert bad" style="margin-top:12px;"><?php echo htmlspecialchars($error); ?></div>
<?php endif; ?>
<form method="post" style="display:grid; gap:12px; margin-top:12px;">
<div>
<label for="email">Email</label>
<input type="email" id="email" name="email" required placeholder="admin@example.com">
</div>
<div>
<label for="password">Password</label>
<input type="password" id="password" name="password" required placeholder="••••••••">
</div>
<button class="btn primary" type="submit">Login</button>
<p class="body muted" style="font-size:13px;">Default admin: ravi@stratawiz.com / qwerty</p>
</form>
</div>
</div>
</main>
<?php require __DIR__ . '/../includes/admin-footer.php'; ?>

View File

@ -1,5 +0,0 @@
<?php
require_once __DIR__ . '/../includes/auth.php';
logout();
header('Location: /admin/login.php');
exit;

View File

@ -1,85 +0,0 @@
<?php
require_once __DIR__ . '/../includes/auth.php';
require_login();
$subs = get_subscriptions();
$isExport = isset($_GET['export']);
if ($isExport) {
header('Content-Type: text/csv');
header('Content-Disposition: attachment; filename="newsletter.csv"');
$out = fopen('php://output', 'w');
fputcsv($out, ['First Name', 'Email', 'Subscribed']);
foreach ($subs as $s) {
fputcsv($out, [
$s['first_name'] ?? '',
$s['email'] ?? '',
$s['created_at'] ?? '',
]);
}
fclose($out);
exit;
}
$assetPathPrefix = '../';
$pageTitle = 'Newsletter Subscribers';
$currentPage = 'news';
$extraStyles = <<<CSS
<style>
body { background: #f6faf7; }
.admin-shell { padding: 40px 0; }
.table { width: 100%; border-collapse: collapse; margin-top: 20px; }
.table th, .table td { text-align: left; padding: 12px 10px; border-bottom: 1px solid #e1ede7; }
.table th { color: #0f4333; }
</style>
CSS;
require __DIR__ . '/../includes/admin-header.php';
?>
<main class="admin-shell">
<div class="container">
<div class="topbar" style="display:flex; justify-content:space-between; align-items:center; margin-bottom:16px;">
<div>
<p class="eyebrow">Newsletter</p>
<h2>Subscription list</h2>
</div>
<div class="btn ghost" style="pointer-events:none;">Read-only</div>
</div>
<div class="admin-nav">
<a href="/admin/tutorials.php">Tutorials</a>
<a href="/admin/sessions.php">Upcoming Sessions</a>
<a href="/admin/contacts.php">Contact Entries</a>
<a href="/admin/newsletter.php">Newsletter</a>
<a href="/admin/admins.php">Admins</a>
<a href="/admin/logout.php">Logout (<?php echo htmlspecialchars(current_admin_email() ?? ''); ?>)</a>
</div>
<div style="margin:10px 0;">
<a class="btn outline small" href="?export=1">Export CSV</a>
</div>
<?php if (empty($subs)): ?>
<p class="body muted">No subscribers yet.</p>
<?php else: ?>
<table class="table">
<thead>
<tr>
<th>First Name</th>
<th>Email</th>
<th>Subscribed</th>
</tr>
</thead>
<tbody>
<?php foreach ($subs as $sub): ?>
<tr>
<td><?php echo htmlspecialchars($sub['first_name'] ?? ''); ?></td>
<td><?php echo htmlspecialchars($sub['email']); ?></td>
<td><?php echo htmlspecialchars($sub['created_at']); ?></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<?php endif; ?>
</div>
</main>
<?php require __DIR__ . '/../includes/admin-footer.php'; ?>

View File

@ -1,191 +0,0 @@
<?php
require_once __DIR__ . '/../includes/auth.php';
require_login();
$error = '';
$uploadDir = __DIR__ . '/../uploads/';
if (!is_dir($uploadDir)) {
mkdir($uploadDir, 0775, true);
}
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$title = trim($_POST['title'] ?? '');
$summary = trim($_POST['summary'] ?? '');
$label = trim($_POST['label'] ?? '');
$video_url = trim($_POST['video_url'] ?? '');
$file_path = null;
if (isset($_FILES['resource_file']) && $_FILES['resource_file']['error'] !== UPLOAD_ERR_NO_FILE) {
$file = $_FILES['resource_file'];
if ($file['error'] === UPLOAD_ERR_OK) {
$allowed = [
'application/pdf',
'application/msword',
'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
];
$finfo = finfo_open(FILEINFO_MIME_TYPE);
$mime = finfo_file($finfo, $file['tmp_name']);
finfo_close($finfo);
if (!in_array($mime, $allowed, true)) {
$error = 'Only PDF or Word documents are allowed.';
} else {
$ext = pathinfo($file['name'], PATHINFO_EXTENSION);
$newName = 'resource_' . time() . '_' . mt_rand(1000, 9999) . '.' . $ext;
$dest = $uploadDir . $newName;
if (move_uploaded_file($file['tmp_name'], $dest)) {
$file_path = 'uploads/' . $newName;
} else {
$error = 'File upload failed.';
}
}
} else {
$error = 'File upload failed.';
}
}
if ($title === '' || $summary === '' || $label === '') {
$error = 'All fields are required.';
} elseif (!$error) {
add_resource(compact('title', 'summary', 'label', 'file_path', 'video_url'));
header('Location: resources.php?success=1');
exit;
}
}
if (isset($_GET['delete'])) {
$id = (int) $_GET['delete'];
delete_resource($id);
header('Location: resources.php?deleted=1');
exit;
}
$resources = get_resources();
echo '<pre>'; print_r($resources); exit;
$assetPathPrefix = '../';
$pageTitle = 'Manage Resources';
$currentPage = 'resources';
$extraStyles = <<<CSS
<style>
body { background: #f6faf7; }
.admin-shell { padding: 40px 0; }
.table { width: 100%; border-collapse: collapse; margin-top: 20px; }
.table th, .table td { text-align: left; padding: 12px 10px; border-bottom: 1px solid #e1ede7; }
.table th { color: #0f4333; }
.badge { display: inline-block; padding: 6px 10px; border-radius: 10px; background: #e8f5ef; color: #0f4333; font-weight: 700; font-size: 13px; }
.inline-btn { color: #b9342f; font-weight: 700; }
form textarea { min-height: 120px; resize: vertical; }
form input, form textarea { width: 100%; padding: 12px 14px; border-radius: 10px; border: 1px solid #d8e7e0; font-size: 15px; margin-top: 8px; }
form input[type=file] { padding: 8px; }
form label { font-weight: 700; color: #0f4333; display: block; margin-top: 12px; }
.topbar { display: flex; justify-content: space-between; align-items: center; margin-bottom: 16px; }
</style>
CSS;
require __DIR__ . '/../includes/admin-header.php';
?>
<main class="admin-shell">
<div class="container">
<div class="topbar">
<div>
<p class="eyebrow">Resources</p>
<h2>Resources for Learning and Research</h2>
<p class="body">Add short descriptions and labels; they will appear instantly on the public site.</p>
</div>
<button class="btn primary" onclick="document.getElementById('resource-form').scrollIntoView({behavior: 'smooth'})">Add new</button>
</div>
<div class="admin-nav">
<a href="/admin/tutorials.php">Tutorials</a>
<a href="/admin/sessions.php">Upcoming Sessions</a>
<a href="/admin/contacts.php">Contact Entries</a>
<a href="/admin/newsletter.php">Newsletter</a>
<a href="/admin/admins.php">Admins</a>
<a href="/admin/logout.php">Logout (<?php echo htmlspecialchars(current_admin_email() ?? ''); ?>)</a>
</div>
<?php if (isset($_GET['success'])): ?>
<div class="alert good">Resource added successfully.</div>
<?php endif; ?>
<?php if (isset($_GET['deleted'])): ?>
<div class="alert good">Resource deleted.</div>
<?php endif; ?>
<?php if ($error): ?>
<div class="alert bad"><?php echo htmlspecialchars($error); ?></div>
<?php endif; ?>
<?php if (empty($resources)): ?>
<p class="body muted">No resources yet. Add your first entry below.</p>
<?php else: ?>
<table class="table">
<thead>
<tr>
<th>Title</th>
<th>Summary</th>
<th>Label</th>
<th>Asset</th>
<th></th>
</tr>
</thead>
<tbody>
<?php foreach ($resources as $index => $resource): ?>
<?php
if (!is_array($resource)) {
continue;
}
$title = htmlspecialchars((string)($resource['title'] ?? ''), ENT_QUOTES, 'UTF-8');
$summary = htmlspecialchars((string)($resource['summary'] ?? ''), ENT_QUOTES, 'UTF-8');
$label = htmlspecialchars((string)($resource['label'] ?? ''), ENT_QUOTES, 'UTF-8');
$filePath = (string)($resource['file_path'] ?? '');
$videoUrl = (string)($resource['video_url'] ?? '');
?>
<tr>
<td><?php echo $title; ?></td>
<td><?php echo $summary; ?></td>
<td><span class="badge"><?php echo $label; ?></span></td>
<td>
<?php if ($filePath): ?>
<a class="text-link" href="/<?php echo htmlspecialchars(ltrim($filePath, '/'), ENT_QUOTES, 'UTF-8'); ?>" target="_blank">Download</a>
<?php elseif ($videoUrl): ?>
<a class="text-link" href="<?php echo htmlspecialchars($videoUrl, ENT_QUOTES, 'UTF-8'); ?>" target="_blank">Watch</a>
<?php else: ?>
<span class="body muted">None</span>
<?php endif; ?>
</td>
<td><a class="inline-btn" href="?delete=<?php echo (int)$resource['id']; ?>" onclick="return confirm('Delete this resource?')">Delete</a></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<?php endif; ?>
<section id="resource-form" style="margin-top:32px;">
<div class="card">
<h3>Add Resource</h3>
<form method="post" enctype="multipart/form-data">
<label for="title">Title</label>
<input type="text" id="title" name="title" required placeholder="Resource title">
<label for="summary">Summary</label>
<textarea id="summary" name="summary" required placeholder="Brief description"></textarea>
<label for="label">Label / Type</label>
<input type="text" id="label" name="label" required placeholder="e.g., Publication, Toolkit">
<label for="video_url">YouTube / Video URL (optional)</label>
<input type="url" id="video_url" name="video_url" placeholder="https://youtube.com/...">
<label for="resource_file">Upload PDF / Word (optional)</label>
<input type="file" id="resource_file" name="resource_file" accept=".pdf,.doc,.docx">
<p class="body muted" style="margin:6px 0 0;">Upload a file or provide a video URL (or both).</p>
<div style="margin-top:16px;">
<button type="submit" class="btn primary">Save resource</button>
<a class="text-link" href="../index.php" style="margin-left:10px;">View live site</a>
</div>
</form>
</div>
</section>
</div>
</main>
<?php require __DIR__ . '/../includes/admin-footer.php'; ?>

View File

@ -1,163 +0,0 @@
<?php
require_once __DIR__ . '/../includes/auth.php';
require_login();
$error = '';
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$title = trim($_POST['title'] ?? '');
$description = trim($_POST['description'] ?? '');
$tag = trim($_POST['tag'] ?? '');
$cta_label = trim($_POST['cta_label'] ?? 'Register');
$start_date = $_POST['start_date'] ?? null;
$editId = isset($_POST['id']) ? (int) $_POST['id'] : null;
if ($title === '' || $description === '') {
$error = 'Title and description are required.';
} else {
if ($editId) {
update_session($editId, compact('title', 'description', 'tag', 'cta_label', 'start_date'));
header('Location: sessions.php?updated=1');
} else {
add_session(compact('title', 'description', 'tag', 'cta_label', 'start_date'));
header('Location: sessions.php?success=1');
}
exit;
}
}
if (isset($_GET['delete'])) {
$id = (int) $_GET['delete'];
delete_session($id);
header('Location: sessions.php?deleted=1');
exit;
}
$sessions = get_sessions();
$editing = null;
if (isset($_GET['edit'])) {
$editId = (int) $_GET['edit'];
foreach ($sessions as $row) {
if ((int) $row['id'] === $editId) {
$editing = $row;
break;
}
}
}
$assetPathPrefix = '../';
$pageTitle = 'Manage Sessions';
$currentPage = 'news';
$extraStyles = <<<CSS
<style>
body { background: #f6faf7; }
.admin-shell { padding: 40px 0; }
.table { width: 100%; border-collapse: collapse; margin-top: 20px; }
.table th, .table td { text-align: left; padding: 12px 10px; border-bottom: 1px solid #e1ede7; }
.table th { color: #0f4333; }
.badge { display: inline-block; padding: 6px 10px; border-radius: 10px; background: #e8f5ef; color: #0f4333; font-weight: 700; font-size: 13px; }
.inline-btn { color: #b9342f; font-weight: 700; }
form textarea { min-height: 120px; resize: vertical; }
form input, form textarea { width: 100%; padding: 12px 14px; border-radius: 10px; border: 1px solid #d8e7e0; font-size: 15px; margin-top: 8px; }
form label { font-weight: 700; color: #0f4333; display: block; margin-top: 12px; }
.topbar { display: flex; justify-content: space-between; align-items: center; margin-bottom: 16px; }
</style>
CSS;
require __DIR__ . '/../includes/admin-header.php';
?>
<main class="admin-shell">
<div class="container">
<div class="topbar">
<div>
<p class="eyebrow">Upcoming Sessions</p>
<h2>Manage events and workshops</h2>
<p class="body">Add session details to show on the public site.</p>
</div>
<button class="btn primary" onclick="document.getElementById('session-form').scrollIntoView({behavior:'smooth'})">Add new</button>
</div>
<div class="admin-nav">
<a href="/admin/tutorials.php">Tutorials</a>
<a href="/admin/sessions.php">Upcoming Sessions</a>
<a href="/admin/contacts.php">Contact Entries</a>
<a href="/admin/newsletter.php">Newsletter</a>
<a href="/admin/admins.php">Admins</a>
<a href="/admin/logout.php">Logout (<?php echo htmlspecialchars(current_admin_email() ?? ''); ?>)</a>
</div>
<?php if (isset($_GET['success'])): ?>
<div class="alert good">Session added successfully.</div>
<?php endif; ?>
<?php if (isset($_GET['deleted'])): ?>
<div class="alert good">Session deleted.</div>
<?php endif; ?>
<?php if (isset($_GET['updated'])): ?>
<div class="alert good">Session updated.</div>
<?php endif; ?>
<?php if ($error): ?>
<div class="alert bad"><?php echo htmlspecialchars($error); ?></div>
<?php endif; ?>
<?php if (empty($sessions)): ?>
<p class="body muted">No sessions yet. Add your first event below.</p>
<?php else: ?>
<table class="table">
<thead>
<tr>
<th>Title</th>
<th>Description</th>
<th>Tag</th>
<th>Start Date</th>
<th></th>
</tr>
</thead>
<tbody>
<?php foreach ($sessions as $session): ?>
<tr>
<td><?php echo htmlspecialchars($session['title']); ?></td>
<td><?php echo htmlspecialchars($session['description']); ?></td>
<td><?php echo htmlspecialchars($session['tag']); ?></td>
<td><?php echo htmlspecialchars($session['start_date'] ?? ''); ?></td>
<td>
<a class="inline-btn" href="?edit=<?php echo (int)$session['id']; ?>">Edit</a> |
<a class="inline-btn" href="?delete=<?php echo (int)$session['id']; ?>" onclick="return confirm('Delete this session?')">Delete</a>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<?php endif; ?>
<section id="session-form" style="margin-top:32px;">
<div class="card">
<h3><?php echo $editing ? 'Edit Session' : 'Add Session'; ?></h3>
<form method="post">
<?php if ($editing): ?>
<input type="hidden" name="id" value="<?php echo (int)$editing['id']; ?>">
<?php endif; ?>
<label for="title">Title</label>
<input type="text" id="title" name="title" required placeholder="Session title" value="<?php echo htmlspecialchars($editing['title'] ?? '', ENT_QUOTES, 'UTF-8'); ?>">
<label for="description">Description</label>
<textarea id="description" name="description" required placeholder="Brief description"><?php echo htmlspecialchars($editing['description'] ?? '', ENT_QUOTES, 'UTF-8'); ?></textarea>
<label for="tag">Tag</label>
<input type="text" id="tag" name="tag" placeholder="e.g., New, Upcoming" value="<?php echo htmlspecialchars($editing['tag'] ?? '', ENT_QUOTES, 'UTF-8'); ?>">
<label for="cta_label">CTA Label</label>
<input type="text" id="cta_label" name="cta_label" placeholder="Register" value="<?php echo htmlspecialchars($editing['cta_label'] ?? 'Register', ENT_QUOTES, 'UTF-8'); ?>">
<label for="start_date">Start Date</label>
<input type="date" id="start_date" name="start_date" value="<?php echo htmlspecialchars($editing['start_date'] ?? '', ENT_QUOTES, 'UTF-8'); ?>">
<div style="margin-top:16px;">
<button type="submit" class="btn primary"><?php echo $editing ? 'Update session' : 'Save session'; ?></button>
<a class="text-link" href="/news-events.php" style="margin-left:10px;">View live</a>
</div>
</form>
</div>
</section>
</div>
</main>
<?php require __DIR__ . '/../includes/admin-footer.php'; ?>

View File

@ -1,222 +0,0 @@
<?php
require_once __DIR__ . '/../includes/auth.php';
require_login();
$error = '';
$uploadDir = __DIR__ . '/../uploads/';
if (!is_dir($uploadDir)) {
mkdir($uploadDir, 0775, true);
}
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$title = trim($_POST['title'] ?? '');
$description = trim($_POST['description'] ?? '');
$status = trim($_POST['status'] ?? 'active');
$video_url = trim($_POST['video_url'] ?? '');
$file_path = null;
$editId = isset($_POST['id']) ? (int) $_POST['id'] : null;
if (isset($_FILES['tutorial_file']) && $_FILES['tutorial_file']['error'] !== UPLOAD_ERR_NO_FILE) {
$file = $_FILES['tutorial_file'];
if ($file['error'] === UPLOAD_ERR_OK) {
$allowed = [
'application/pdf',
'application/msword',
'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
];
$finfo = finfo_open(FILEINFO_MIME_TYPE);
$mime = finfo_file($finfo, $file['tmp_name']);
finfo_close($finfo);
if (!in_array($mime, $allowed, true)) {
$error = 'Only PDF or Word documents are allowed.';
} else {
$ext = pathinfo($file['name'], PATHINFO_EXTENSION);
$newName = 'tutorial_' . time() . '_' . mt_rand(1000, 9999) . '.' . $ext;
$dest = $uploadDir . $newName;
if (move_uploaded_file($file['tmp_name'], $dest)) {
$file_path = 'uploads/' . $newName;
} else {
$error = 'File upload failed.';
}
}
} else {
$error = 'File upload failed.';
}
}
if ($title === '' || $description === '') {
$error = 'Title and description are required.';
} elseif (!$error) {
$payload = compact('title', 'description', 'status', 'file_path', 'video_url');
if ($editId) {
update_tutorial($editId, $payload);
header('Location: tutorials.php?updated=1');
} else {
add_tutorial($payload);
header('Location: tutorials.php?success=1');
}
exit;
}
}
if (isset($_GET['delete'])) {
$id = (int) $_GET['delete'];
delete_tutorial($id);
header('Location: tutorials.php?deleted=1');
exit;
}
$tutorials = get_tutorials(false);
$editing = null;
if (isset($_GET['edit'])) {
$editId = (int) $_GET['edit'];
foreach ($tutorials as $row) {
if ((int) $row['id'] === $editId) {
$editing = $row;
break;
}
}
}
$assetPathPrefix = '../';
$pageTitle = 'Manage Tutorials';
$currentPage = 'tutorials';
$extraStyles = <<<CSS
<style>
body { background: #f6faf7; }
.admin-shell { padding: 40px 0; }
.table { width: 100%; border-collapse: collapse; margin-top: 20px; }
.table th, .table td { text-align: left; padding: 12px 10px; border-bottom: 1px solid #e1ede7; }
.table th { color: #0f4333; }
.badge { display: inline-block; padding: 6px 10px; border-radius: 10px; background: #e8f5ef; color: #0f4333; font-weight: 700; font-size: 13px; }
.inline-btn { color: #b9342f; font-weight: 700; }
form textarea { min-height: 120px; resize: vertical; }
form input, form textarea, form select { width: 100%; padding: 12px 14px; border-radius: 10px; border: 1px solid #d8e7e0; font-size: 15px; margin-top: 8px; }
form input[type=file] { padding: 8px; }
form label { font-weight: 700; color: #0f4333; display: block; margin-top: 12px; }
.topbar { display: flex; justify-content: space-between; align-items: center; margin-bottom: 16px; }
</style>
CSS;
require __DIR__ . '/../includes/admin-header.php';
?>
<main class="admin-shell">
<div class="container">
<div class="topbar">
<div>
<p class="eyebrow">Tutorials</p>
<h2>Manage tutorials</h2>
<p class="body">Add training tutorials with downloads or video links.</p>
</div>
<button class="btn primary" onclick="document.getElementById('tutorial-form').scrollIntoView({behavior: 'smooth'})">Add new</button>
</div>
<div class="admin-nav">
<a href="/admin/tutorials.php">Tutorials</a>
<a href="/admin/sessions.php">Upcoming Sessions</a>
<a href="/admin/contacts.php">Contact Entries</a>
<a href="/admin/newsletter.php">Newsletter</a>
<a href="/admin/admins.php">Admins</a>
<a href="/admin/logout.php">Logout (<?php echo htmlspecialchars(current_admin_email() ?? ''); ?>)</a>
</div>
<?php if (isset($_GET['success'])): ?>
<div class="alert good">Tutorial added successfully.</div>
<?php endif; ?>
<?php if (isset($_GET['deleted'])): ?>
<div class="alert good">Tutorial deleted.</div>
<?php endif; ?>
<?php if (isset($_GET['updated'])): ?>
<div class="alert good">Tutorial updated successfully.</div>
<?php endif; ?>
<?php if ($error): ?>
<div class="alert bad"><?php echo htmlspecialchars($error); ?></div>
<?php endif; ?>
<?php if (empty($tutorials)): ?>
<p class="body muted">No tutorials yet. Add your first entry below.</p>
<?php else: ?>
<table class="table">
<thead>
<tr>
<th>Title</th>
<th>Description</th>
<th>Status</th>
<th>Asset</th>
<th></th>
</tr>
</thead>
<tbody>
<?php foreach ($tutorials as $tutorial): ?>
<?php
if (!is_array($tutorial)) {
continue;
}
$title = htmlspecialchars((string)($tutorial['title'] ?? ''), ENT_QUOTES, 'UTF-8');
$description = htmlspecialchars((string)($tutorial['description'] ?? ''), ENT_QUOTES, 'UTF-8');
$status = htmlspecialchars((string)($tutorial['status'] ?? ''), ENT_QUOTES, 'UTF-8');
$filePath = (string)($tutorial['file_path'] ?? '');
$videoUrl = (string)($tutorial['video_url'] ?? '');
?>
<tr>
<td><?php echo $title; ?></td>
<td><?php echo $description; ?></td>
<td><span class="badge"><?php echo $status; ?></span></td>
<td>
<?php if ($filePath): ?>
<a class="text-link" href="/<?php echo htmlspecialchars(ltrim($filePath, '/'), ENT_QUOTES, 'UTF-8'); ?>" target="_blank">Download</a>
<?php elseif ($videoUrl): ?>
<a class="text-link" href="<?php echo htmlspecialchars($videoUrl, ENT_QUOTES, 'UTF-8'); ?>" target="_blank">Watch</a>
<?php else: ?>
<span class="body muted">None</span>
<?php endif; ?>
</td>
<td>
<a class="inline-btn" href="?edit=<?php echo (int)$tutorial['id']; ?>">Edit</a> |
<a class="inline-btn" href="?delete=<?php echo (int)$tutorial['id']; ?>" onclick="return confirm('Delete this tutorial?')">Delete</a>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<?php endif; ?>
<section id="tutorial-form" style="margin-top:32px;">
<div class="card">
<h3><?php echo $editing ? 'Edit Tutorial' : 'Add Tutorial'; ?></h3>
<form method="post" enctype="multipart/form-data">
<?php if ($editing): ?>
<input type="hidden" name="id" value="<?php echo (int)$editing['id']; ?>">
<?php endif; ?>
<label for="title">Title</label>
<input type="text" id="title" name="title" required placeholder="Tutorial title" value="<?php echo htmlspecialchars($editing['title'] ?? '', ENT_QUOTES, 'UTF-8'); ?>">
<label for="description">Description</label>
<textarea id="description" name="description" required placeholder="Brief description"><?php echo htmlspecialchars($editing['description'] ?? '', ENT_QUOTES, 'UTF-8'); ?></textarea>
<label for="status">Status</label>
<select id="status" name="status">
<option value="active" <?php echo (($editing['status'] ?? '') === 'active') ? 'selected' : ''; ?>>Active</option>
<option value="draft" <?php echo (($editing['status'] ?? '') === 'draft') ? 'selected' : ''; ?>>Draft</option>
</select>
<label for="video_url">YouTube / Video URL (optional)</label>
<input type="url" id="video_url" name="video_url" placeholder="https://youtube.com/..." value="<?php echo htmlspecialchars($editing['video_url'] ?? '', ENT_QUOTES, 'UTF-8'); ?>">
<label for="tutorial_file">Upload PDF / Word (optional)</label>
<input type="file" id="tutorial_file" name="tutorial_file" accept=".pdf,.doc,.docx">
<?php if (!empty($editing['file_path'])): ?>
<p class="body muted">Current file: <a href="/<?php echo htmlspecialchars($editing['file_path'], ENT_QUOTES, 'UTF-8'); ?>" target="_blank">Download</a></p>
<?php endif; ?>
<p class="body muted" style="margin:6px 0 0;">Upload a file or provide a video URL (or both).</p>
<div style="margin-top:16px;">
<button type="submit" class="btn primary"><?php echo $editing ? 'Update tutorial' : 'Save tutorial'; ?></button>
<a class="text-link" href="/index.php" style="margin-left:10px;">View live site</a>
</div>
</form>
</div>
</section>
</div>
</main>
<?php require __DIR__ . '/../includes/admin-footer.php'; ?>

View File

@ -1,113 +0,0 @@
body.admin-body {
background: #f6faf7;
font-family: 'Inter', 'Segoe UI', system-ui, -apple-system, sans-serif;
color: #0e1e18;
}
.site-header {
background: #ffffff;
}
.brand-mark {
width: 42px;
height: 42px;
border-radius: 12px;
background: linear-gradient(135deg, #2bc08a, #11704f);
}
.brand-name {
font-size: 18px;
}
.brand-tagline {
font-size: 12px;
}
.admin-shell {
padding: 40px 0;
}
.admin-nav {
display: flex;
gap: 10px;
flex-wrap: wrap;
margin: 10px 0 20px;
}
.admin-nav a {
background: #e6f3ed;
color: #0f4333;
padding: 8px 12px;
border-radius: 10px;
font-weight: 700;
text-decoration: none;
}
.card {
border-radius: 16px;
border: 1px solid #e5efe9;
box-shadow: 0 10px 24px rgba(20, 72, 55, 0.08);
padding: 16px;
}
.btn.primary,
.btn.btn-primary {
background: #1d9c6d;
color: #fff;
border: none;
}
.btn.outline,
.btn.btn-outline {
background: #fff;
border: 1px solid #d3e8e0;
color: #0f4333;
}
.btn.small {
padding: 8px 12px;
border-radius: 10px;
}
form input,
form textarea,
form select {
width: 100%;
padding: 12px 14px;
border-radius: 10px;
border: 1px solid #d8e7e0;
font-size: 15px;
margin-top: 8px;
}
form textarea {
min-height: 120px;
resize: vertical;
}
form label {
font-weight: 700;
color: #0f4333;
display: block;
margin-top: 12px;
}
.alert.good {
background: #def3eb;
color: #0f4333;
}
.alert.bad {
background: #ffebe8;
color: #9a2f23;
}
.table th,
.table td {
vertical-align: top;
}
.admin-footer {
background: #f0f5f3;
border-top: 1px solid #e0ebe5;
}

View File

@ -1,73 +0,0 @@
.brand-mark {
width: 42px;
height: 42px;
background: linear-gradient(135deg, #2bc08a, #11704f);
border-radius: 12px;
}
.hero-section {
background: radial-gradient(140% 120% at 25% 20%, #e9f7f0 0%, #ffffff 60%);
}
.stat-tile {
background: #eef8f5;
border: 1px solid #def3eb;
}
.hero-orb {
width: 220px;
height: 220px;
border-radius: 50%;
background: radial-gradient(circle at 30% 30%, #ffb7a6, #e06a6a 60%);
display: grid;
place-items: center;
box-shadow: 0 18px 40px rgba(223, 121, 121, 0.35);
}
.hero-orb-inner {
width: 120px;
height: 120px;
background: linear-gradient(180deg, #ffede7, #ffb9a6);
border-radius: 12px;
}
.icon-pill {
width: 42px;
height: 42px;
border-radius: 12px;
background: #e8f5ef;
color: #0f6f52;
display: grid;
place-items: center;
font-weight: 700;
}
.placeholder-img {
min-height: 200px;
background: linear-gradient(135deg, #c2e7d9, #9cd3c3);
}
.placeholder-img.tall { min-height: 260px; }
.placeholder-img.small { min-height: 140px; }
.placeholder-img.mailer {
min-height: 220px;
background: linear-gradient(135deg, #f6f6f6, #ffffff);
box-shadow: 0 12px 30px rgba(0,0,0,0.08);
}
.dot {
width: 10px;
height: 10px;
border-radius: 50%;
display: inline-block;
}
.badge.bg-success-subtle {
background: #e8f5ef !important;
color: #0f6f52 !important;
}
.card {
border-radius: 16px;
}
.footer a { color: #fff; }

View File

@ -1,8 +0,0 @@
document.addEventListener('DOMContentLoaded', () => {
const form = document.querySelector('.newsletter-form');
if (form) {
form.addEventListener('submit', () => {
// Let the form submit normally; no client-side prevention so server can record subscriptions.
});
}
});

View File

@ -1,72 +0,0 @@
<?php
require_once __DIR__ . '/includes/data.php';
$pageTitle = 'Contact | CREST';
$metaDescription = 'Contact CREST for research collaborations, training, media, or partnership inquiries in respiratory health.';
$contactMessage = '';
$contactError = '';
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$name = trim($_POST['name'] ?? '');
$email = trim($_POST['email'] ?? '');
$organization = trim($_POST['organization'] ?? '');
$message = trim($_POST['message'] ?? '');
if ($name === '' || $email === '' || $message === '') {
$contactError = 'Name, email, and message are required.';
} elseif (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
$contactError = 'Please enter a valid email.';
} else {
save_contact(compact('name', 'email', 'organization', 'message'));
$contactMessage = 'Thanks for reaching out. We will get back to you within 2 business days.';
}
}
include __DIR__ . '/includes/site-header.php';
?>
<main>
<section class="py-5">
<div class="container">
<div class="row g-4">
<div class="col-md-6">
<p class="text-uppercase text-success fw-bold small mb-1">Contact</p>
<h2 class="fw-bold">We would love to hear from you</h2>
<p class="text-muted">Tell us about your research needs, training goals, or partnership ideas.</p>
<ul class="list-unstyled">
<li class="mb-2">• Program design consultations</li>
<li class="mb-2">• Training calendar requests</li>
<li class="mb-2">• Media and speaking inquiries</li>
</ul>
</div>
<div class="col-md-6">
<div class="card shadow-sm border-0 rounded-4 p-3">
<?php if ($contactMessage): ?>
<div class="alert alert-success"><?php echo htmlspecialchars($contactMessage); ?></div>
<?php elseif ($contactError): ?>
<div class="alert alert-danger"><?php echo htmlspecialchars($contactError); ?></div>
<?php endif; ?>
<form class="row g-3" method="post">
<div class="col-12">
<input type="text" name="name" class="form-control rounded-3" placeholder="Full Name" required>
</div>
<div class="col-12">
<input type="email" name="email" class="form-control rounded-3" placeholder="Email" required>
</div>
<div class="col-12">
<input type="text" name="organization" class="form-control rounded-3" placeholder="Organization">
</div>
<div class="col-12">
<textarea name="message" class="form-control rounded-3" rows="4" placeholder="How can we help?" required></textarea>
</div>
<div class="col-12 d-grid">
<button class="btn btn-success text-white rounded-3" type="submit">Send message</button>
</div>
</form>
</div>
</div>
</div>
</div>
</section>
</main>
<?php include __DIR__ . '/includes/site-footer.php'; ?>

View File

@ -1,22 +0,0 @@
[
{
"title": "Understanding Lung Function in Adult Populations",
"summary": "A concise explainer on spirometry metrics and how to interpret lung function assessments in community settings.",
"label": "Publication"
},
{
"title": "Lung Function in India: Overview",
"summary": "Key findings from multi-city research that maps prevalence of respiratory conditions across demographic groups.",
"label": "Research Brief"
},
{
"title": "Childhood Lung Function in India",
"summary": "Practical guidance for pediatric screening teams and frontline clinicians working with young patients.",
"label": "Toolkit"
},
{
"title": "Understanding Lung Function in Rural Populations",
"summary": "Field notes and methodologies for conducting door-to-door lung health studies with limited resources.",
"label": "Field Guide"
}
]

View File

@ -1,48 +0,0 @@
<?php
require_once __DIR__ . '/includes/data.php';
$pageTitle = 'Our Expertise | CREST';
$metaDescription = 'Discover CREST services in research, training, and consulting for respiratory health programs.';
include __DIR__ . '/includes/site-header.php';
?>
<main>
<section class="py-5 bg-light">
<div class="container">
<div class="mb-4">
<p class="text-uppercase text-success fw-bold small mb-1">Our Expertise</p>
<h2 class="fw-bold">Our Services &amp; Expertise</h2>
</div>
<div class="row g-3">
<div class="col-md-4">
<div class="card h-100 shadow-sm border-0 rounded-4">
<div class="card-body">
<div class="icon-pill mb-3">★</div>
<h5 class="fw-bold">Research</h5>
<p class="text-muted small">Rigorous studies to map lung health trends and inform community programs.</p>
</div>
</div>
</div>
<div class="col-md-4">
<div class="card h-100 shadow-sm border-0 rounded-4">
<div class="card-body">
<div class="icon-pill mb-3">★</div>
<h5 class="fw-bold">Training</h5>
<p class="text-muted small">Workshops and mentoring that upskill clinicians and field teams.</p>
</div>
</div>
</div>
<div class="col-md-4">
<div class="card h-100 shadow-sm border-0 rounded-4">
<div class="card-body">
<div class="icon-pill mb-3">★</div>
<h5 class="fw-bold">Consulting</h5>
<p class="text-muted small">Advisory for programs to scale respiratory care safely and effectively.</p>
</div>
</div>
</div>
</div>
</div>
</section>
</main>
<?php include __DIR__ . '/includes/site-footer.php'; ?>

View File

@ -1,28 +0,0 @@
<?php
$pageTitle = 'Our Experts | Crest Lung Health';
$currentPage = 'experts';
require __DIR__ . '/includes/header.php';
?>
<main>
<section class="section">
<div class="container two-col">
<div>
<p class="eyebrow">Our Experts</p>
<h1>Meet the team driving respiratory innovation</h1>
<p class="body">Clinical specialists, researchers, and educators collaborate to design programs that translate science into care. Each team member brings domain expertise across pulmonology, epidemiology, community health, and implementation.</p>
<ul class="checklist">
<li><span class="dot green"></span> 300+ specialists and faculty contributors</li>
<li><span class="dot green"></span> Cross-functional teams for research and training</li>
<li><span class="dot green"></span> Field experience across diverse geographies</li>
</ul>
</div>
<div class="photo-card">
<div class="photo tall"></div>
<div class="photo caption">Trusted by leading institutes</div>
</div>
</div>
</section>
</main>
<?php require __DIR__ . '/includes/footer.php'; ?>

View File

@ -1,9 +0,0 @@
<footer class="admin-footer">
<div class="container text-center small text-muted py-3">
©2025 Stratawiz.com
</div>
</footer>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
<script src="<?php echo $assetPathPrefix; ?>assets/js/main.js"></script>
</body>
</html>

View File

@ -1,33 +0,0 @@
<?php
if (session_status() === PHP_SESSION_NONE) {
session_start();
}
$assetPathPrefix = $assetPathPrefix ?? '';
$pageTitle = $pageTitle ?? 'Admin';
$loggedEmail = $_SESSION['admin_email'] ?? null;
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title><?php echo htmlspecialchars($pageTitle); ?></title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css">
<link rel="stylesheet" href="<?php echo $assetPathPrefix; ?>assets/css/admin.css">
<?php if (!empty($extraStyles)) { echo $extraStyles; } ?>
</head>
<body class="admin-body">
<header class="site-header shadow-sm">
<div class="container d-flex justify-content-between align-items-center py-3">
<div class="d-flex align-items-center gap-2">
<div class="brand-mark text-white fw-bold d-flex align-items-center justify-content-center">C</div>
<div>
<div class="brand-name text-success fw-bold">CREST</div>
<div class="brand-tagline text-muted">Admin Panel</div>
</div>
</div>
<div class="fw-semibold text-muted">
<?php echo $loggedEmail ? htmlspecialchars($loggedEmail) : ''; ?>
</div>
</div>
</header>

View File

@ -1,50 +0,0 @@
<?php
require_once __DIR__ . '/data.php';
if (session_status() === PHP_SESSION_NONE) {
session_start();
}
function require_login(): void
{
if (!is_logged_in()) {
$loginPath = 'login.php';
if (strpos($_SERVER['REQUEST_URI'] ?? '', '/admin/') === false) {
$loginPath = '/admin/login.php';
}
header('Location: ' . $loginPath);
exit;
}
}
function is_logged_in(): bool
{
return isset($_SESSION['admin_id']);
}
function current_admin_email(): ?string
{
return $_SESSION['admin_email'] ?? null;
}
function attempt_login(string $email, string $password): bool
{
$admin = get_admin_by_email($email);
if (!$admin) {
return false;
}
if (password_verify($password, $admin['password_hash'])) {
$_SESSION['admin_id'] = $admin['id'];
$_SESSION['admin_email'] = $admin['email'];
return true;
}
return false;
}
function logout(): void
{
$_SESSION = [];
session_destroy();
}

View File

@ -1,229 +0,0 @@
<?php
require_once __DIR__ . '/db.php';
if (!function_exists('get_resources')) {
function get_resources(): array
{
$pdo = db();
$table = resource_table_name($pdo);
try {
$rows = $pdo->query("SELECT * FROM resources_table ORDER BY id DESC");
return is_array($rows) ? $rows : [];
} catch (Throwable $e) {
error_log('get_resources attempt failed: ' . $e->getMessage());
return [];
}
}
}
if (!function_exists('add_resource')) {
function add_resource(array $payload): void
{
$pdo = db();
$table = resource_table_name($pdo);
$pdo->insert($table, [
'title' => trim($payload['title'] ?? ''),
'summary' => trim($payload['summary'] ?? ''),
'label' => trim($payload['label'] ?? ''),
'file_path' => $payload['file_path'] ?? null,
'video_url' => trim($payload['video_url'] ?? ''),
]);
}
}
if (!function_exists('delete_resource')) {
function delete_resource(int $id): void
{
$pdo = db();
$table = resource_table_name($pdo);
$filePath = null;
$row = $pdo->getOne("SELECT file_path FROM `$table` WHERE id = ?", [$id]);
if ($row && isset($row['file_path'])) {
$filePath = $row['file_path'];
}
$pdo->deleteById($table, $id);
if ($filePath && is_string($filePath)) {
$full = __DIR__ . '/../' . ltrim($filePath, '/');
if (is_file($full)) {
@unlink($full);
}
}
}
}
if (!function_exists('get_sessions')) {
function get_sessions(): array
{
$pdo = db();
$rows = $pdo->query("
SELECT id, number, start_date, status, join_link, code, venue
FROM sessions
WHERE (status IN ('current','upcoming') OR start_date >= NOW())
AND (deleted_at IS NULL OR deleted_at = '0000-00-00 00:00:00')
ORDER BY start_date ASC
");
return is_array($rows) ? $rows : [];
}
}
if (!function_exists('add_session')) {
function add_session(array $payload): void
{
$pdo = db();
$pdo->insert('sessions', [
'title' => trim($payload['title'] ?? ''),
'description' => trim($payload['description'] ?? ''),
'tag' => trim($payload['tag'] ?? ''),
'cta_label' => trim($payload['cta_label'] ?? 'Register'),
'start_date' => $payload['start_date'] ?? null,
]);
}
}
if (!function_exists('update_session')) {
function update_session(int $id, array $payload): void
{
$pdo = db();
$pdo->update('sessions', [
'title' => trim($payload['title'] ?? ''),
'description' => trim($payload['description'] ?? ''),
'tag' => trim($payload['tag'] ?? ''),
'cta_label' => trim($payload['cta_label'] ?? 'Register'),
'start_date' => $payload['start_date'] ?? null,
], "id = ?", [$id]);
}
}
if (!function_exists('delete_session')) {
function delete_session(int $id): void
{
$pdo = db();
$pdo->deleteById('sessions', $id);
}
}
if (!function_exists('save_contact')) {
function save_contact(array $payload): void
{
$pdo = db();
$pdo->insert('contacts', [
'name' => trim($payload['name'] ?? ''),
'email' => trim($payload['email'] ?? ''),
'organization' => trim($payload['organization'] ?? ''),
'message' => trim($payload['message'] ?? ''),
]);
}
}
if (!function_exists('get_contacts')) {
function get_contacts(): array
{
$pdo = db();
return $pdo->query("SELECT id, name, email, organization, message, created_at FROM contacts ORDER BY id DESC");
}
}
if (!function_exists('get_tutorials')) {
function get_tutorials(bool $onlyActive = true): array
{
$pdo = db();
$sql = "SELECT id, title, description, status, file_path, video_url, created_at FROM tutorials";
$params = [];
if ($onlyActive) {
$sql .= " WHERE status = ?";
$params[] = 'active';
}
$sql .= " ORDER BY id DESC";
$rows = $pdo->query($sql, $params);
return is_array($rows) ? $rows : [];
}
}
if (!function_exists('add_tutorial')) {
function add_tutorial(array $payload): void
{
$pdo = db();
$pdo->insert('tutorials', [
'title' => trim($payload['title'] ?? ''),
'description' => trim($payload['description'] ?? ''),
'status' => trim($payload['status'] ?? 'active'),
'file_path' => $payload['file_path'] ?? null,
'video_url' => trim($payload['video_url'] ?? ''),
]);
}
}
if (!function_exists('update_tutorial')) {
function update_tutorial(int $id, array $payload): void
{
$pdo = db();
$data = [
'title' => trim($payload['title'] ?? ''),
'description' => trim($payload['description'] ?? ''),
'status' => trim($payload['status'] ?? 'active'),
'video_url' => trim($payload['video_url'] ?? ''),
];
if (!empty($payload['file_path'])) {
$data['file_path'] = $payload['file_path'];
}
$pdo->update('tutorials', $data, "id = ?", [$id]);
}
}
if (!function_exists('delete_tutorial')) {
function delete_tutorial(int $id): void
{
$pdo = db();
$row = $pdo->getOne("SELECT file_path FROM tutorials WHERE id = ?", [$id]);
$filePath = $row['file_path'] ?? null;
$pdo->deleteById('tutorials', $id);
if ($filePath && is_string($filePath)) {
$full = __DIR__ . '/../' . ltrim($filePath, '/');
if (is_file($full)) {
@unlink($full);
}
}
}
}
if (!function_exists('save_subscription')) {
function save_subscription(array $payload): void
{
$pdo = db();
$pdo->rawQuery(
"INSERT INTO newsletter_subscriptions (first_name, email) VALUES (?, ?) ON DUPLICATE KEY UPDATE first_name = VALUES(first_name)",
[
trim($payload['first_name'] ?? ''),
trim($payload['email'] ?? ''),
]
);
}
}
if (!function_exists('get_subscriptions')) {
function get_subscriptions(): array
{
$pdo = db();
return $pdo->query("SELECT id, first_name, email, created_at FROM newsletter_subscriptions ORDER BY id DESC");
}
}
if (!function_exists('get_admin_by_email')) {
function get_admin_by_email(string $email): ?array
{
$pdo = db();
$row = $pdo->getOne("SELECT * FROM admins WHERE email = ?", [$email]);
return $row ?: null;
}
}
if (!function_exists('create_admin')) {
function create_admin(string $email, string $password): void
{
$pdo = db();
$hash = password_hash($password, PASSWORD_DEFAULT);
$pdo->insert('admins', ['email' => $email, 'password_hash' => $hash]);
}
}

View File

@ -1,223 +0,0 @@
<?php
require_once __DIR__ . '/mysqli-class.php';
function db(): MysqliDb
{
static $db = null;
if ($db instanceof MysqliDb) {
return $db;
}
$user = 'virtualuser';
$pass = 'ltnwGXZqvQJqXjPPQgmO';
$dbName = 'shabby_road';
$host = 'virtualengage.c1qdknkurtfn.ap-south-1.rds.amazonaws.com';
$port = 3306;
$attempts = [
['socket' => null, 'host' => $host, 'port' => $port],
];
$lastError = '';
foreach ($attempts as $attempt) {
try {
$db = new MysqliDb([
'host' => $attempt['host'],
'username' => $user,
'password' => $pass,
'db' => $dbName,
'port' => $attempt['port'],
'socket' => $attempt['socket'],
'charset' => 'utf8mb4',
]);
bootstrap_schema($db);
return $db;
} catch (Exception $e) {
$lastError = $e->getMessage();
}
}
throw new Exception('Database connection failed: ' . $lastError);
}
function bootstrap_schema(MysqliDb $db): void
{
$db->rawQuery("CREATE TABLE IF NOT EXISTS admins (
id INT AUTO_INCREMENT PRIMARY KEY,
email VARCHAR(255) NOT NULL UNIQUE,
password_hash VARCHAR(255) NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)");
$resourceTable = ensure_resources_table($db);
$db->rawQuery("CREATE TABLE IF NOT EXISTS sessions (
id INT AUTO_INCREMENT PRIMARY KEY,
title VARCHAR(255) NOT NULL,
description TEXT NOT NULL,
tag VARCHAR(50) DEFAULT NULL,
cta_label VARCHAR(100) DEFAULT 'Register',
start_date DATE DEFAULT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)");
$db->rawQuery("CREATE TABLE IF NOT EXISTS contacts (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(255) NOT NULL,
email VARCHAR(255) NOT NULL,
organization VARCHAR(255) DEFAULT NULL,
message TEXT NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)");
$db->rawQuery("CREATE TABLE IF NOT EXISTS newsletter_subscriptions (
id INT AUTO_INCREMENT PRIMARY KEY,
first_name VARCHAR(255) DEFAULT NULL,
email VARCHAR(255) NOT NULL UNIQUE,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)");
$db->rawQuery("CREATE TABLE IF NOT EXISTS tutorials (
id INT AUTO_INCREMENT PRIMARY KEY,
title VARCHAR(255) NOT NULL,
description TEXT NOT NULL,
status VARCHAR(50) NOT NULL DEFAULT 'active',
file_path VARCHAR(255) DEFAULT NULL,
video_url VARCHAR(255) DEFAULT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)");
seed_default_admin($db);
seed_sample_resources($db, $resourceTable);
seed_sample_sessions($db);
seed_sample_tutorials($db);
}
function seed_default_admin(MysqliDb $db): void
{
$row = $db->getOne("SELECT 1 FROM admins WHERE email = ?", ['ravi@stratawiz.com']);
if ($row) {
return;
}
$hash = password_hash('qwerty', PASSWORD_DEFAULT);
$db->insert('admins', ['email' => 'ravi@stratawiz.com', 'password_hash' => $hash]);
}
function seed_sample_resources(MysqliDb $db, string $table): void
{
$count = (int) $db->getValue("SELECT COUNT(*) as c FROM `$table`");
if ($count > 0) {
return;
}
$samples = [
['title' => 'Understanding Lung Function in Adult Populations', 'summary' => 'A concise explainer on spirometry metrics and how to interpret lung function assessments in community settings.', 'label' => 'Publication'],
['title' => 'Lung Function in India: Overview', 'summary' => 'Key findings from multi-city research that maps prevalence of respiratory conditions across demographic groups.', 'label' => 'Research Brief'],
['title' => 'Childhood Lung Function in India', 'summary' => 'Practical guidance for pediatric screening teams and frontline clinicians working with young patients.', 'label' => 'Toolkit'],
['title' => 'Understanding Lung Function in Rural Populations', 'summary' => 'Field notes and methodologies for conducting door-to-door lung health studies with limited resources.', 'label' => 'Field Guide'],
];
foreach ($samples as $sample) {
$db->insert($table, $sample);
}
}
function seed_sample_sessions(MysqliDb $db): void
{
$count = (int) $db->getValue("SELECT COUNT(*) as c FROM sessions");
if ($count > 0) {
return;
}
$samples = [
['title' => 'Nutrition guidance for advanced lung conditions', 'description' => 'Upcoming webinar on dietary support for patients with complex respiratory conditions.', 'tag' => 'New'],
['title' => 'Workshop: Field data quality for respiratory studies', 'description' => 'Hands-on clinic for research leads to strengthen field protocols and audits.', 'tag' => 'Update'],
['title' => 'Training cohort launch: Spirometry essentials', 'description' => 'New batch begins soon with live mentoring and case reviews.', 'tag' => 'Upcoming'],
];
foreach ($samples as $sample) {
$db->insert('sessions', $sample);
}
}
function seed_sample_tutorials(MysqliDb $db): void
{
$count = (int) $db->getValue("SELECT COUNT(*) as c FROM tutorials");
if ($count > 0) {
return;
}
$samples = [
['title' => 'Spirometry Basics', 'description' => 'Step-by-step guide for accurate spirometry setup and testing.', 'status' => 'active'],
['title' => 'Inhaler Technique', 'description' => 'Visual walkthrough on patient education for inhaler use.', 'status' => 'active'],
];
foreach ($samples as $sample) {
$db->insert('tutorials', $sample);
}
}
function ensure_resources_table(MysqliDb $db): string
{
$candidates = ['resources_table', 'resources'];
// Prefer any existing table that already has rows.
foreach ($candidates as $name) {
$exists = $db->getValue("SELECT 1 FROM information_schema.tables WHERE table_schema = DATABASE() AND table_name = ?", [$name]);
if ($exists) {
$count = (int) $db->getValue("SELECT COUNT(*) FROM `$name`");
if ($count > 0) {
add_resource_columns_if_missing($db, $name);
return $name;
}
}
}
// Fallback to first existing, even if empty.
foreach ($candidates as $name) {
$exists = $db->getValue("SELECT 1 FROM information_schema.tables WHERE table_schema = DATABASE() AND table_name = ?", [$name]);
if ($exists) {
add_resource_columns_if_missing($db, $name);
return $name;
}
}
$name = 'resources';
$db->rawQuery("CREATE TABLE IF NOT EXISTS `$name` (
id INT AUTO_INCREMENT PRIMARY KEY,
title VARCHAR(255) NOT NULL,
summary TEXT NOT NULL,
label VARCHAR(100) NOT NULL,
file_path VARCHAR(255) DEFAULT NULL,
video_url VARCHAR(255) DEFAULT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)");
add_resource_columns_if_missing($db, $name);
return $name;
}
function add_resource_columns_if_missing(MysqliDb $db, string $table): void
{
$columns = [
'file_path' => 'ALTER TABLE `%s` ADD COLUMN file_path VARCHAR(255) DEFAULT NULL',
'video_url' => 'ALTER TABLE `%s` ADD COLUMN video_url VARCHAR(255) DEFAULT NULL',
];
foreach ($columns as $column => $alter) {
$exists = $db->getValue("SELECT 1 FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = ? AND column_name = ?", [$table, $column]);
if (!$exists) {
$db->rawQuery(sprintf($alter, $table));
}
}
}
function resource_table_name(MysqliDb $db): string
{
static $resolved;
if ($resolved) {
return $resolved;
}
$resolved = ensure_resources_table($db);
return $resolved;
}

View File

@ -1,12 +0,0 @@
<footer class="site-footer">
<div class="copyright">
@ CREST - Chest Research and Training Pyt Lad ·
<a href="#">Privacy Policy</a> |
<a href="#">Terms of use</a> |
<a href="#">Linkin</a>
</div>
</footer>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
<script src="<?php echo $assetPathPrefix; ?>assets/js/main.js"></script>
</body>
</html>

View File

@ -1,46 +0,0 @@
<?php
$assetPathPrefix = $assetPathPrefix ?? '';
$pageTitle = $pageTitle ?? 'Crest Lung Health';
$currentPage = $currentPage ?? '';
$navItems = [
['key' => 'home', 'label' => 'Home', 'href' => $assetPathPrefix . 'index.php'],
['key' => 'experts', 'label' => 'Our Experts', 'href' => $assetPathPrefix . 'experts.php'],
['key' => 'services', 'label' => 'Our Services', 'href' => $assetPathPrefix . 'services.php'],
['key' => 'training', 'label' => 'Training', 'href' => $assetPathPrefix . 'training.php'],
['key' => 'achievements', 'label' => 'Achievements', 'href' => $assetPathPrefix . 'achievements.php'],
['key' => 'resources', 'label' => 'Resources', 'href' => $assetPathPrefix . 'resources.php'],
['key' => 'news', 'label' => 'News & Events', 'href' => $assetPathPrefix . 'news-events.php'],
['key' => 'contact', 'label' => 'Contact', 'href' => $assetPathPrefix . 'contact.php'],
];
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title><?php echo htmlspecialchars($pageTitle); ?></title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css">
<link rel="stylesheet" href="<?php echo $assetPathPrefix; ?>assets/css/style.css">
<?php if (!empty($extraStyles)) { echo $extraStyles; } ?>
</head>
<body>
<header class="site-header">
<div class="container nav-bar">
<div class="brand">
<div class="brand-mark">C</div>
<div>
<div class="brand-name">CREST</div>
<div class="brand-tagline">Cancer Research Training & Consultancy</div>
</div>
</div>
<nav class="nav">
<?php foreach ($navItems as $item): ?>
<a href="<?php echo htmlspecialchars($item['href']); ?>"
class="<?php echo $currentPage === $item['key'] ? 'active' : ''; ?>">
<?php echo htmlspecialchars($item['label']); ?>
</a>
<?php endforeach; ?>
</nav>
</div>
</header>

View File

@ -1,138 +0,0 @@
<?php
class MysqliDb
{
/** @var mysqli */
private $conn;
public function __construct(array $config)
{
$host = $config['host'] ?? '127.0.0.1';
$user = $config['username'] ?? 'root';
$pass = $config['password'] ?? '';
$db = $config['db'] ?? '';
$port = $config['port'] ?? null;
$socket = $config['socket'] ?? null;
$charset = $config['charset'] ?? 'utf8mb4';
$this->conn = @new mysqli($host, $user, $pass, $db, $port ?? ini_get("mysqli.default_port"), $socket);
if ($this->conn->connect_errno) {
throw new Exception('MySQL connection error: ' . $this->conn->connect_error);
}
$this->conn->set_charset($charset);
}
/**
* @return array|bool
*/
public function rawQuery(string $sql, array $params = [])
{
if (empty($params)) {
$result = $this->conn->query($sql);
if ($result === false) {
throw new Exception('Query error: ' . $this->conn->error);
}
if ($result === true) {
return true;
}
$data = $result->fetch_all(MYSQLI_ASSOC);
$result->free();
return $data;
}
$stmt = $this->prepareAndBind($sql, $params);
if (!$stmt->execute()) {
throw new Exception('Query error: ' . $stmt->error);
}
$res = $stmt->get_result();
$rows = $res ? $res->fetch_all(MYSQLI_ASSOC) : [];
$stmt->close();
return $rows;
}
/**
* @return array|bool
*/
public function query(string $sql, array $params = [])
{
return $this->rawQuery($sql, $params);
}
/**
* @return array|null
*/
public function getOne(string $sql, array $params = [])
{
$rows = $this->rawQuery($sql, $params);
return $rows[0] ?? null;
}
public function getValue(string $sql, array $params = [])
{
$row = $this->getOne($sql, $params);
if (!$row) {
return null;
}
return array_shift($row);
}
public function insert(string $table, array $data): int
{
$cols = array_keys($data);
$placeholders = implode(',', array_fill(0, count($cols), '?'));
$colList = '`' . implode('`,`', $cols) . '`';
$sql = "INSERT INTO `$table` ($colList) VALUES ($placeholders)";
$stmt = $this->prepareAndBind($sql, array_values($data));
if (!$stmt->execute()) {
throw new Exception('Insert error: ' . $stmt->error);
}
$id = $stmt->insert_id ?: $this->conn->insert_id;
$stmt->close();
return (int) $id;
}
public function deleteById(string $table, int $id): bool
{
$stmt = $this->prepareAndBind("DELETE FROM `$table` WHERE id = ?", [$id]);
$ok = $stmt->execute();
$stmt->close();
return $ok;
}
public function update(string $table, array $data, string $where, array $params = []): bool
{
$sets = [];
$values = [];
foreach ($data as $col => $val) {
$sets[] = "`$col` = ?";
$values[] = $val;
}
$sql = "UPDATE `$table` SET " . implode(',', $sets) . " WHERE $where";
$bind = array_merge($values, $params);
$stmt = $this->prepareAndBind($sql, $bind);
$ok = $stmt->execute();
$stmt->close();
return $ok;
}
private function prepareAndBind(string $sql, array $params): mysqli_stmt
{
$stmt = $this->conn->prepare($sql);
if (!$stmt) {
throw new Exception('Prepare failed: ' . $this->conn->error);
}
if (!empty($params)) {
$types = '';
$refs = [];
foreach ($params as $param) {
$types .= is_int($param) ? 'i' : (is_float($param) ? 'd' : 's');
}
$refs[] = &$types;
foreach ($params as $k => $v) {
$refs[] = &$params[$k];
}
$stmt->bind_param(...$refs);
}
return $stmt;
}
}

View File

@ -1,14 +0,0 @@
<footer class="bg-success text-white py-3 mt-5">
<div class="container d-flex flex-wrap justify-content-between">
<small>@ CREST - Chest Research and Training Pyt Lad</small>
<div class="d-flex gap-3 small">
<a href="#" class="text-white text-decoration-none">Privacy Policy</a>
<a href="#" class="text-white text-decoration-none">Terms of use</a>
<a href="#" class="text-white text-decoration-none">Linkin</a>
</div>
</div>
</footer>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
<script src="assets/js/main.js"></script>
</body>
</html>

View File

@ -1,50 +0,0 @@
<?php
$pageTitle = $pageTitle ?? 'CREST';
$metaDescription = $metaDescription ?? 'CREST advances respiratory health through research, training, and collaboration.';
$canonical = '';
if (!empty($_SERVER['HTTP_HOST']) && !empty($_SERVER['REQUEST_URI'])) {
$scheme = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? 'https' : 'http';
$canonical = $scheme . '://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="description" content="<?php echo htmlspecialchars($metaDescription, ENT_QUOTES, 'UTF-8'); ?>">
<meta name="robots" content="index,follow">
<meta property="og:title" content="<?php echo htmlspecialchars($pageTitle, ENT_QUOTES, 'UTF-8'); ?>">
<meta property="og:description" content="<?php echo htmlspecialchars($metaDescription, ENT_QUOTES, 'UTF-8'); ?>">
<?php if ($canonical): ?><link rel="canonical" href="<?php echo htmlspecialchars($canonical, ENT_QUOTES, 'UTF-8'); ?>"><?php endif; ?>
<title><?php echo htmlspecialchars($pageTitle); ?></title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="assets/css/style.css">
</head>
<body>
<nav class="navbar navbar-expand-lg bg-body-tertiary shadow-sm sticky-top">
<div class="container">
<a class="navbar-brand d-flex align-items-center gap-2" href="index.php">
<div class="brand-mark text-white fw-bold d-flex align-items-center justify-content-center">C</div>
<div>
<div class="fw-bold text-success m-0 lh-1">CREST</div>
<small class="text-muted d-block" style="font-size:12px;">Chest Research and Training</small>
</div>
</a>
<button class="navbar-toggler border-0" type="button" data-bs-toggle="collapse" data-bs-target="#mainNav" aria-controls="mainNav" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="mainNav">
<ul class="navbar-nav ms-auto mb-2 mb-lg-0 small fw-semibold">
<li class="nav-item"><a class="nav-link text-muted" href="index.php">Home</a></li>
<li class="nav-item"><a class="nav-link text-muted" href="who-we-are.php">Who we are</a></li>
<li class="nav-item"><a class="nav-link text-muted" href="expertise.php">Our Expertise</a></li>
<li class="nav-item"><a class="nav-link text-muted" href="training.php">Training</a></li>
<li class="nav-item"><a class="nav-link text-muted" href="achievements.php">Achievements</a></li>
<li class="nav-item"><a class="nav-link text-muted" href="resources.php">Resources</a></li>
<li class="nav-item"><a class="nav-link text-muted" href="work-with-us.php">Work with us</a></li>
<li class="nav-item"><a class="nav-link text-muted" href="contact.php">Contact</a></li>
</ul>
</div>
</div>
</nav>

View File

@ -1,282 +0,0 @@
<?php
require_once __DIR__ . '/includes/data.php';
$resources = get_tutorials(); // reuse tutorials data for resources section
$sessions = get_sessions();
$pageTitle = 'CREST | Chest Research and Training';
$metaDescription = 'Explore CREST respiratory research, training programs, events, and downloadable resources to strengthen lung health initiatives.';
include __DIR__ . '/includes/site-header.php';
?>
<main>
<section class="hero-section py-5">
<div class="container">
<div class="row g-4 align-items-center">
<div class="col-lg-6">
<p class="text-uppercase text-success fw-bold small mb-1">Transforming Respiratory Health Through</p>
<h1 class="fw-bold lh-1">Research, Training &amp; Innovation</h1>
<p class="text-muted mb-4">Advancing the science of lung health to create a healthier India.</p>
<div class="d-flex flex-wrap gap-2 mb-4">
<a class="btn btn-outline-secondary rounded-3" href="#resources">Browse services</a>
<a class="btn btn-success text-white rounded-3" href="#contact">Get in touch</a>
</div>
<div class="row row-cols-2 row-cols-md-3 row-cols-lg-5 g-2">
<div class="col">
<div class="stat-tile text-center p-3 h-100 rounded-4 bg-light-subtle">
<div class="fw-bold">1Mn+</div>
<div class="text-muted small">Lives touched</div>
</div>
</div>
<div class="col">
<div class="stat-tile text-center p-3 h-100 rounded-4 bg-light-subtle">
<div class="fw-bold">5k+</div>
<div class="text-muted small">Doctors trained</div>
</div>
</div>
<div class="col">
<div class="stat-tile text-center p-3 h-100 rounded-4 bg-light-subtle">
<div class="fw-bold">500+</div>
<div class="text-muted small">Medical schools</div>
</div>
</div>
<div class="col">
<div class="stat-tile text-center p-3 h-100 rounded-4 bg-light-subtle">
<div class="fw-bold">300+</div>
<div class="text-muted small">Research studies</div>
</div>
</div>
<div class="col">
<div class="stat-tile text-center p-3 h-100 rounded-4 bg-light-subtle">
<div class="fw-bold">50+</div>
<div class="text-muted small">New research</div>
</div>
</div>
</div>
</div>
<div class="col-lg-6 text-center">
<div class="hero-orb mx-auto mb-3">
<div class="hero-orb-inner"></div>
</div>
<span class="badge text-bg-dark px-3 py-2 rounded-pill">Lab ready</span>
</div>
</div>
</div>
</section>
<section class="py-5" id="who">
<div class="container">
<div class="row g-4 align-items-center">
<div class="col-md-5">
<div class="rounded-4 bg-light-subtle p-4 h-100 d-flex flex-column justify-content-between">
<div class="placeholder-img flex-grow-1 rounded-4 mb-3"></div>
<div class="d-flex align-items-center gap-2">
<span class="badge bg-success-subtle text-success fw-semibold">300+</span>
<span class="small text-muted">consultants &amp; specialists</span>
</div>
</div>
</div>
<div class="col-md-7">
<p class="text-uppercase text-success fw-bold small mb-1">Who we are</p>
<h2 class="fw-bold">Grounded in data, inspired by care</h2>
<p class="text-muted">We are a multidisciplinary team working at the intersection of research, training, and respiratory medicine. From field studies to clinical education, we help organizations make lung health programs measurable, effective, and equitable.</p>
<ul class="list-unstyled mb-3">
<li class="d-flex align-items-center gap-2 mb-2">
<span class="dot bg-success"></span>
<span class="fw-semibold">Modern Research Device</span>
</li>
<li class="d-flex align-items-center gap-2 mb-2">
<span class="dot bg-warning"></span>
<span class="fw-semibold">World Class laboratory</span>
</li>
</ul>
<a class="btn btn-success text-white rounded-3" href="#expertise">Learn more</a>
</div>
</div>
</div>
</section>
<section class="py-5 bg-light" id="expertise">
<div class="container">
<div class="d-flex flex-wrap justify-content-between align-items-center mb-4">
<div>
<p class="text-uppercase text-success fw-bold small mb-1">Our Expertise</p>
<h3 class="fw-bold">Our Services &amp; Expertise</h3>
</div>
</div>
<div class="row g-3">
<div class="col-md-4">
<div class="card h-100 shadow-sm border-0 rounded-4">
<div class="card-body">
<div class="icon-pill mb-3">★</div>
<h5 class="fw-bold">Research</h5>
<p class="text-muted small mb-3">Rigorous studies to map lung health trends and inform community programs.</p>
<a class="text-success fw-semibold small" href="#">Learn more</a>
</div>
</div>
</div>
<div class="col-md-4">
<div class="card h-100 shadow-sm border-0 rounded-4">
<div class="card-body">
<div class="icon-pill mb-3">★</div>
<h5 class="fw-bold">Training</h5>
<p class="text-muted small mb-3">Workshops and mentoring that upskill clinicians and field teams.</p>
<a class="text-success fw-semibold small" href="#">Learn more</a>
</div>
</div>
</div>
<div class="col-md-4">
<div class="card h-100 shadow-sm border-0 rounded-4">
<div class="card-body">
<div class="icon-pill mb-3">★</div>
<h5 class="fw-bold">Consulting</h5>
<p class="text-muted small mb-3">Advisory for programs to scale respiratory care safely and effectively.</p>
<a class="text-success fw-semibold small" href="#">Learn more</a>
</div>
</div>
</div>
</div>
</div>
</section>
<section class="py-5" id="training">
<div class="container">
<div class="row g-4 align-items-center">
<div class="col-lg-6">
<h3 class="fw-bold">Training Program</h3>
<p class="text-muted">Our modular training brings together research-backed content, case-based discussions, and practical skill-building so teams can lead respiratory health initiatives confidently.</p>
<ul class="list-unstyled text-muted small mb-3">
<li class="mb-1">• Research Training</li>
<li class="mb-1">• Spirometry &amp; Lung Function Testing</li>
<li class="mb-1">• Critical Situations</li>
<li class="mb-1">• Audit Program</li>
<li class="mb-1">• Quality Assurance</li>
</ul>
<a class="btn btn-success text-white rounded-3">Join the training</a>
</div>
<div class="col-lg-6">
<div class="rounded-4 bg-light-subtle p-3">
<div class="placeholder-img tall rounded-4 mb-3"></div>
<span class="badge bg-success-subtle text-success fw-semibold">100+ batch completions</span>
</div>
</div>
</div>
</div>
</section>
<section class="py-5 bg-body" id="events">
<div class="container">
<div class="d-flex flex-wrap justify-content-between align-items-center mb-4">
<div>
<p class="text-uppercase text-success fw-bold small mb-1">Latest Events</p>
<h3 class="fw-bold">Latest Events</h3>
</div>
<a class="btn btn-outline-success" href="sessions-list.php">View all events</a>
</div>
<?php if (empty($sessions)): ?>
<p class="text-muted">No upcoming sessions yet. Check back soon.</p>
<?php else: ?>
<div class="row g-3">
<?php foreach ($sessions as $session): ?>
<?php
if (!is_array($session)) { continue; }
$number = htmlspecialchars((string)($session['number'] ?? ''), ENT_QUOTES, 'UTF-8');
$startDate = !empty($session['start_date']) ? date('M d, Y', strtotime($session['start_date'])) : '';
$venue = htmlspecialchars((string)($session['venue'] ?? ''), ENT_QUOTES, 'UTF-8');
$code = htmlspecialchars((string)($session['code'] ?? ''), ENT_QUOTES, 'UTF-8');
$regLink = $code ? "https://road.xltr.in/register/{$code}" : '#';
?>
<div class="col-md-4">
<div class="card h-100 shadow-sm border-0 rounded-4">
<div class="placeholder-img small rounded-top-4"></div>
<div class="card-body position-relative">
<span class="badge bg-white border text-success position-absolute top-0 end-0 m-3">Upcoming</span>
<h6 class="fw-bold mt-3">Session <?php echo $number ?: 'N/A'; ?></h6>
<?php if ($startDate): ?><p class="text-muted small mb-1">Starts: <?php echo $startDate; ?></p><?php endif; ?>
<?php if ($venue): ?><p class="text-muted small mb-2">Venue: <?php echo $venue; ?></p><?php endif; ?>
<a class="btn btn-outline-success btn-sm mt-2" href="<?php echo $regLink; ?>" target="_blank">Register</a>
</div>
</div>
</div>
<?php endforeach; ?>
</div>
<?php endif; ?>
</div>
</section>
<section class="py-5" id="resources">
<div class="container">
<div class="mb-4">
<p class="text-uppercase text-success fw-bold small mb-1">Resources for Learning and Research</p>
<h3 class="fw-bold">Resources for Learning and Research</h3>
<p class="text-muted small">Well-curated resources to explore our work and keep you up to date on our research.</p>
</div>
<?php if (empty($resources)): ?>
<p class="text-muted">No resources yet.</p>
<?php else: ?>
<div class="row g-3">
<?php foreach ($resources as $resource): ?>
<?php
if (!is_array($resource)) { continue; }
$label = htmlspecialchars((string)($resource['label'] ?? ''), ENT_QUOTES, 'UTF-8');
$title = htmlspecialchars((string)($resource['title'] ?? ''), ENT_QUOTES, 'UTF-8');
$summary = htmlspecialchars((string)($resource['description'] ?? ''), ENT_QUOTES, 'UTF-8');
$filePath = isset($resource['file_path']) ? (string)$resource['file_path'] : '';
$videoUrl = isset($resource['video_url']) ? (string)$resource['video_url'] : '';
?>
<div class="col-md-6">
<div class="card h-100 shadow-sm border-0 rounded-4 p-3">
<span class="badge bg-success-subtle text-success fw-semibold mb-2"><?php echo $label; ?></span>
<h6 class="fw-bold"><?php echo $title; ?></h6>
<p class="text-muted small mb-3"><?php echo $summary; ?></p>
<div class="d-flex gap-2 flex-wrap">
<?php if ($filePath): ?>
<a class="btn btn-outline-success btn-sm" href="<?php echo htmlspecialchars(ltrim($filePath, '/'), ENT_QUOTES, 'UTF-8'); ?>" target="_blank">Download</a>
<?php endif; ?>
<?php if ($videoUrl): ?>
<a class="btn btn-success btn-sm text-white" href="<?php echo htmlspecialchars($videoUrl, ENT_QUOTES, 'UTF-8'); ?>" target="_blank">Watch</a>
<?php endif; ?>
<?php if (!$filePath && !$videoUrl): ?>
<span class="text-muted small">No download yet</span>
<?php endif; ?>
</div>
</div>
</div>
<?php endforeach; ?>
</div>
<?php endif; ?>
</div>
</section>
<section class="py-5 bg-success-subtle" id="contact">
<div class="container">
<div class="row g-4 align-items-center">
<div class="col-lg-6">
<p class="text-uppercase text-success fw-bold small mb-1">Subscribe</p>
<h3 class="fw-bold">Subscribe to Regular Newsletters.</h3>
<p class="text-muted">Get curated research insights and training updates straight to your inbox.</p>
<?php if (!empty($newsletterMessage)): ?>
<div class="alert alert-success p-2"><?php echo htmlspecialchars($newsletterMessage); ?></div>
<?php elseif (!empty($newsletterError)): ?>
<div class="alert alert-danger p-2"><?php echo htmlspecialchars($newsletterError); ?></div>
<?php endif; ?>
<form class="row g-2" method="post">
<div class="col-md-4">
<input type="text" class="form-control rounded-3" name="newsletter_name" placeholder="First Name">
</div>
<div class="col-md-5">
<input type="email" class="form-control rounded-3" name="newsletter_email" placeholder="Email" required>
</div>
<div class="col-md-3 d-grid">
<button class="btn btn-success text-white rounded-3" type="submit">Subscribe</button>
</div>
</form>
</div>
<div class="col-lg-6 text-center">
<div class="placeholder-img mailer rounded-4"></div>
</div>
</div>
</div>
</section>
</main>
<?php include __DIR__ . '/includes/site-footer.php'; ?>

View File

@ -1,41 +0,0 @@
<?php
require_once __DIR__ . '/includes/data.php';
$pageTitle = 'News & Events | CREST';
$metaDescription = 'Stay updated on CREST respiratory health events and upcoming training sessions.';
$sessions = get_sessions();
include __DIR__ . '/includes/site-header.php';
?>
<main>
<section class="py-5 bg-light">
<div class="container">
<p class="text-uppercase text-success fw-bold small mb-1">News &amp; Events</p>
<h1 class="fw-bold">Latest updates, workshops, and announcements</h1>
<?php if (empty($sessions)): ?>
<p class="text-muted" style="margin-top:16px;">No sessions announced yet. Check back soon.</p>
<?php else: ?>
<div class="row g-3" style="margin-top:16px;">
<?php foreach ($sessions as $session): ?>
<?php
$number = htmlspecialchars((string)($session['number'] ?? ''), ENT_QUOTES, 'UTF-8');
$startDate = !empty($session['start_date']) ? date('M d, Y', strtotime($session['start_date'])) : '';
$venue = htmlspecialchars((string)($session['venue'] ?? ''), ENT_QUOTES, 'UTF-8');
$code = htmlspecialchars((string)($session['code'] ?? ''), ENT_QUOTES, 'UTF-8');
$regLink = $code ? "https://road.xltr.in/register/{$code}" : '#';
?>
<article class="card event-card col-md-4">
<div class="placeholder-img small"></div>
<div class="chip">Upcoming</div>
<h3><?php echo $number ? 'Session ' . $number : 'Session'; ?></h3>
<?php if ($startDate): ?><p class="text-muted small mb-1">Starts: <?php echo $startDate; ?></p><?php endif; ?>
<?php if ($venue): ?><p class="text-muted small mb-2">Venue: <?php echo $venue; ?></p><?php endif; ?>
<a class="btn btn-outline-success btn-sm" href="<?php echo $regLink; ?>" target="_blank">Register</a>
</article>
<?php endforeach; ?>
</div>
<?php endif; ?>
</div>
</section>
</main>
<?php include __DIR__ . '/includes/site-footer.php'; ?>

View File

@ -1,56 +0,0 @@
<?php
require_once __DIR__ . '/includes/data.php';
$pageTitle = 'Resources | CREST';
$metaDescription = 'Download CREST respiratory learning resources including tutorials, guides, and video sessions.';
$resources = get_tutorials(false); // reuse tutorials data for resources page
include __DIR__ . '/includes/site-header.php';
?>
<main>
<section class="py-5">
<div class="container">
<p class="text-uppercase text-success fw-bold small mb-1">Resources</p>
<h1 class="fw-bold">Resources for Learning and Research</h1>
<p class="text-muted">Downloadable guides, publications, and toolkits created by our faculty to support your teams.</p>
<?php if (empty($resources)): ?>
<p class="text-muted" style="margin-top:16px;">No resources yet. Check back soon.</p>
<?php else: ?>
<div class="row g-3" style="margin-top:20px;">
<?php foreach ($resources as $resource): ?>
<?php
if (!is_array($resource)) {
continue;
}
$label = htmlspecialchars((string)($resource['label'] ?? ''), ENT_QUOTES, 'UTF-8');
$title = htmlspecialchars((string)($resource['title'] ?? ''), ENT_QUOTES, 'UTF-8');
$summary = htmlspecialchars((string)($resource['description'] ?? ''), ENT_QUOTES, 'UTF-8');
$filePath = isset($resource['file_path']) ? (string)$resource['file_path'] : '';
$videoUrl = isset($resource['video_url']) ? (string)$resource['video_url'] : '';
?>
<div class="col-md-4">
<article class="card h-100 shadow-sm border-0 rounded-4 p-3">
<span class="badge bg-success-subtle text-success fw-semibold mb-2"><?php echo $label ?: 'Resource'; ?></span>
<h3 class="h5 fw-bold"><?php echo $title; ?></h3>
<p class="text-muted small mb-3"><?php echo $summary; ?></p>
<div class="d-flex gap-2 flex-wrap">
<?php if ($filePath): ?>
<a class="btn btn-outline-success btn-sm" href="<?php echo htmlspecialchars(ltrim($filePath, '/'), ENT_QUOTES, 'UTF-8'); ?>" target="_blank">Download</a>
<?php endif; ?>
<?php if ($videoUrl): ?>
<a class="btn btn-success btn-sm text-white" href="<?php echo htmlspecialchars($videoUrl, ENT_QUOTES, 'UTF-8'); ?>" target="_blank">Watch</a>
<?php endif; ?>
<?php if (!$filePath && !$videoUrl): ?>
<span class="text-muted small">No download yet</span>
<?php endif; ?>
</div>
</article>
</div>
<?php endforeach; ?>
</div>
<?php endif; ?>
</div>
</section>
</main>
<?php include __DIR__ . '/includes/site-footer.php'; ?>

View File

@ -1,35 +0,0 @@
<?php
$pageTitle = 'Our Services | Crest Lung Health';
$currentPage = 'services';
require __DIR__ . '/includes/header.php';
?>
<main>
<section class="section light">
<div class="container">
<p class="eyebrow">Our Services</p>
<h1>Integrated solutions for lung health programs</h1>
<p class="body">From research design to clinical training and program evaluation, our services are built to deliver measurable outcomes.</p>
<div class="card-grid" style="margin-top:20px;">
<article class="card">
<div class="icon-pill">R</div>
<h3>Research Design</h3>
<p>Protocol development, ethics submissions, and analytics frameworks tailored to your population.</p>
</article>
<article class="card">
<div class="icon-pill">T</div>
<h3>Training & Upskilling</h3>
<p>Workshops, certifications, and blended learning pathways for clinicians and field teams.</p>
</article>
<article class="card">
<div class="icon-pill">Q</div>
<h3>Quality & Audits</h3>
<p>End-to-end audits, standard operating procedures, and continuous improvement playbooks.</p>
</article>
</div>
</div>
</section>
</main>
<?php require __DIR__ . '/includes/footer.php'; ?>

View File

@ -1,50 +0,0 @@
<?php
require_once __DIR__ . '/includes/data.php';
$pageTitle = 'Events | CREST';
$metaDescription = 'Browse all current and upcoming CREST sessions with dates, venues, and registration links.';
$sessions = get_sessions();
include __DIR__ . '/includes/site-header.php';
?>
<main>
<section class="py-5 bg-light">
<div class="container">
<div class="d-flex flex-wrap justify-content-between align-items-center mb-4">
<div>
<p class="text-uppercase text-success fw-bold small mb-1">Events</p>
<h1 class="fw-bold">Current &amp; Upcoming Sessions</h1>
</div>
</div>
<?php if (empty($sessions)): ?>
<p class="text-muted" style="margin-top:16px;">No sessions announced yet. Check back soon.</p>
<?php else: ?>
<div class="row g-3" style="margin-top:16px;">
<?php foreach ($sessions as $session): ?>
<?php
if (!is_array($session)) { continue; }
$number = htmlspecialchars((string)($session['number'] ?? ''), ENT_QUOTES, 'UTF-8');
$startDate = !empty($session['start_date']) ? date('M d, Y', strtotime($session['start_date'])) : '';
$venue = htmlspecialchars((string)($session['venue'] ?? ''), ENT_QUOTES, 'UTF-8');
$code = htmlspecialchars((string)($session['code'] ?? ''), ENT_QUOTES, 'UTF-8');
$regLink = $code ? "https://road.xltr.in/register/{$code}" : '#';
?>
<div class="col-md-4">
<article class="card event-card h-100">
<div class="placeholder-img small"></div>
<div class="chip">Upcoming</div>
<div class="p-3">
<h5 class="fw-bold"><?php echo $number ? 'Session ' . $number : 'Session'; ?></h5>
<?php if ($startDate): ?><p class="text-muted small mb-1">Starts: <?php echo $startDate; ?></p><?php endif; ?>
<?php if ($venue): ?><p class="text-muted small mb-2">Venue: <?php echo $venue; ?></p><?php endif; ?>
<a class="btn btn-outline-success btn-sm" href="<?php echo $regLink; ?>" target="_blank">Register</a>
</div>
</article>
</div>
<?php endforeach; ?>
</div>
<?php endif; ?>
</div>
</section>
</main>
<?php include __DIR__ . '/includes/site-footer.php'; ?>

View File

@ -1,33 +0,0 @@
<?php
require_once __DIR__ . '/includes/data.php';
$pageTitle = 'Training | CREST';
$metaDescription = 'Join CREST respiratory training programs covering spirometry, critical care, quality assurance, and field research.';
include __DIR__ . '/includes/site-header.php';
?>
<main>
<section class="py-5">
<div class="container">
<div class="row g-4 align-items-center">
<div class="col-lg-6">
<h3 class="fw-bold">Training Program</h3>
<p class="text-muted">Our modular training brings together research-backed content, case-based discussions, and practical skill-building so teams can lead respiratory health initiatives confidently.</p>
<ul class="list-unstyled text-muted small mb-3">
<li class="mb-1">• Research Training</li>
<li class="mb-1">• Spirometry &amp; Lung Function Testing</li>
<li class="mb-1">• Critical Situations</li>
<li class="mb-1">• Audit Program</li>
<li class="mb-1">• Quality Assurance</li>
</ul>
<a class="btn btn-success text-white rounded-3">Join the training</a>
</div>
<div class="col-lg-6">
<div class="placeholder-img tall rounded-4 mb-3"></div>
<span class="badge bg-success-subtle text-success fw-semibold">100+ batch completions</span>
</div>
</div>
</div>
</section>
</main>
<?php include __DIR__ . '/includes/site-footer.php'; ?>

View File

@ -1,30 +0,0 @@
<?php
require_once __DIR__ . '/includes/data.php';
$pageTitle = 'Who we are | CREST';
$metaDescription = 'Learn about CREST and our multidisciplinary team focused on advancing respiratory health through research and training.';
include __DIR__ . '/includes/site-header.php';
?>
<main>
<section class="py-5">
<div class="container">
<div class="row g-4 align-items-center">
<div class="col-md-5">
<div class="placeholder-img tall rounded-4 mb-3"></div>
</div>
<div class="col-md-7">
<p class="text-uppercase text-success fw-bold small mb-1">Who we are</p>
<h2 class="fw-bold">Grounded in data, inspired by care</h2>
<p class="text-muted">We are a multidisciplinary team working at the intersection of research, training, and respiratory medicine. From field studies to clinical education, we help organizations make lung health programs measurable, effective, and equitable.</p>
<ul class="list-unstyled mb-3">
<li class="mb-2">• Modern research device set-up</li>
<li class="mb-2">• World-class laboratory standards</li>
</ul>
<a class="btn btn-success text-white rounded-3" href="expertise.php">Explore expertise</a>
</div>
</div>
</div>
</section>
</main>
<?php include __DIR__ . '/includes/site-footer.php'; ?>

View File

@ -1,43 +0,0 @@
<?php
require_once __DIR__ . '/includes/data.php';
$pageTitle = 'Work with us | CREST';
$metaDescription = 'Partner with CREST for research collaborations, training partnerships, and respiratory program consulting.';
include __DIR__ . '/includes/site-header.php';
?>
<main>
<section class="py-5">
<div class="container">
<h2 class="fw-bold mb-3">Work with us</h2>
<p class="text-muted mb-4">Partner with us on research, training programs, or pilot initiatives to strengthen respiratory health outcomes.</p>
<div class="row g-3">
<div class="col-md-4">
<div class="card shadow-sm border-0 rounded-4 h-100">
<div class="card-body">
<h5 class="fw-bold">Research collaborations</h5>
<p class="text-muted small mb-0">Co-design studies, data collection, and analysis with our research team.</p>
</div>
</div>
</div>
<div class="col-md-4">
<div class="card shadow-sm border-0 rounded-4 h-100">
<div class="card-body">
<h5 class="fw-bold">Training partnerships</h5>
<p class="text-muted small mb-0">Upskill your teams with modular curricula and faculty-led workshops.</p>
</div>
</div>
</div>
<div class="col-md-4">
<div class="card shadow-sm border-0 rounded-4 h-100">
<div class="card-body">
<h5 class="fw-bold">Program consulting</h5>
<p class="text-muted small mb-0">Set up or scale clinics, QA processes, and field operations with our experts.</p>
</div>
</div>
</div>
</div>
</div>
</section>
</main>
<?php include __DIR__ . '/includes/site-footer.php'; ?>