diff --git a/.perm_test_apache b/.perm_test_apache new file mode 100644 index 0000000..e69de29 diff --git a/.perm_test_exec b/.perm_test_exec new file mode 100644 index 0000000..e69de29 diff --git a/ai/LocalAIApi.php b/ai/LocalAIApi.php new file mode 100644 index 0000000..00b1b00 --- /dev/null +++ b/ai/LocalAIApi.php @@ -0,0 +1,311 @@ + [ +// ['role' => 'system', 'content' => 'You are a helpful assistant.'], +// ['role' => 'user', 'content' => 'Tell me a bedtime story.'], +// ], +// ]); +// if (!empty($response['success'])) { +// $decoded = LocalAIApi::decodeJsonFromResponse($response); +// } + +class LocalAIApi +{ + /** @var array|null */ + private static ?array $configCache = null; + + /** + * Signature compatible with the OpenAI Responses API. + * + * @param array $params Request body (model, input, text, reasoning, metadata, etc.). + * @param array $options Extra options (timeout, verify_tls, headers, path, project_uuid). + * @return array{ + * success:bool, + * status?:int, + * data?:mixed, + * error?:string, + * response?:mixed, + * message?:string + * } + */ + public static function createResponse(array $params, array $options = []): array + { + $cfg = self::config(); + $payload = $params; + + if (empty($payload['input']) || !is_array($payload['input'])) { + return [ + 'success' => false, + 'error' => 'input_missing', + 'message' => 'Parameter "input" is required and must be an array.', + ]; + } + + if (!isset($payload['model']) || $payload['model'] === '') { + $payload['model'] = $cfg['default_model']; + } + + return self::request($options['path'] ?? null, $payload, $options); + } + + /** + * Snake_case alias for createResponse (matches the provided example). + * + * @param array $params + * @param array $options + * @return array + */ + public static function create_response(array $params, array $options = []): array + { + return self::createResponse($params, $options); + } + + /** + * Perform a raw request to the AI proxy. + * + * @param string $path Endpoint (may be an absolute URL). + * @param array $payload JSON payload. + * @param array $options Additional request options. + * @return array + */ + public static function request(?string $path = null, array $payload = [], array $options = []): array + { + if (!function_exists('curl_init')) { + return [ + 'success' => false, + 'error' => 'curl_missing', + 'message' => 'PHP cURL extension is missing. Install or enable it on the VM.', + ]; + } + + $cfg = self::config(); + + $projectUuid = $cfg['project_uuid']; + if (empty($projectUuid)) { + return [ + 'success' => false, + 'error' => 'project_uuid_missing', + 'message' => 'PROJECT_UUID is not defined; aborting AI request.', + ]; + } + + $defaultPath = $cfg['responses_path'] ?? null; + $resolvedPath = $path ?? ($options['path'] ?? $defaultPath); + if (empty($resolvedPath)) { + return [ + 'success' => false, + 'error' => 'project_id_missing', + 'message' => 'PROJECT_ID is not defined; cannot resolve AI proxy endpoint.', + ]; + } + + $url = self::buildUrl($resolvedPath, $cfg['base_url']); + $baseTimeout = isset($cfg['timeout']) ? (int) $cfg['timeout'] : 30; + $timeout = isset($options['timeout']) ? (int) $options['timeout'] : $baseTimeout; + if ($timeout <= 0) { + $timeout = 30; + } + + $baseVerifyTls = array_key_exists('verify_tls', $cfg) ? (bool) $cfg['verify_tls'] : true; + $verifyTls = array_key_exists('verify_tls', $options) + ? (bool) $options['verify_tls'] + : $baseVerifyTls; + + $projectHeader = $cfg['project_header']; + + $headers = [ + 'Content-Type: application/json', + 'Accept: application/json', + ]; + $headers[] = $projectHeader . ': ' . $projectUuid; + if (!empty($options['headers']) && is_array($options['headers'])) { + foreach ($options['headers'] as $header) { + if (is_string($header) && $header !== '') { + $headers[] = $header; + } + } + } + + if (!empty($projectUuid) && !array_key_exists('project_uuid', $payload)) { + $payload['project_uuid'] = $projectUuid; + } + + $body = json_encode($payload, JSON_UNESCAPED_UNICODE); + if ($body === false) { + return [ + 'success' => false, + 'error' => 'json_encode_failed', + 'message' => 'Failed to encode request body to JSON.', + ]; + } + + $ch = curl_init($url); + curl_setopt($ch, CURLOPT_POST, true); + curl_setopt($ch, CURLOPT_POSTFIELDS, $body); + curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt($ch, CURLOPT_TIMEOUT, $timeout); + curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5); + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, $verifyTls); + curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, $verifyTls ? 2 : 0); + curl_setopt($ch, CURLOPT_FAILONERROR, false); + + $responseBody = curl_exec($ch); + if ($responseBody === false) { + $error = curl_error($ch) ?: 'Unknown cURL error'; + curl_close($ch); + return [ + 'success' => false, + 'error' => 'curl_error', + 'message' => $error, + ]; + } + + $status = (int) curl_getinfo($ch, CURLINFO_HTTP_CODE); + curl_close($ch); + + $decoded = null; + if ($responseBody !== '' && $responseBody !== null) { + $decoded = json_decode($responseBody, true); + if (json_last_error() !== JSON_ERROR_NONE) { + $decoded = null; + } + } + + if ($status >= 200 && $status < 300) { + return [ + 'success' => true, + 'status' => $status, + 'data' => $decoded ?? $responseBody, + ]; + } + + $errorMessage = 'AI proxy request failed'; + if (is_array($decoded)) { + $errorMessage = $decoded['error'] ?? $decoded['message'] ?? $errorMessage; + } elseif (is_string($responseBody) && $responseBody !== '') { + $errorMessage = $responseBody; + } + + return [ + 'success' => false, + 'status' => $status, + 'error' => $errorMessage, + 'response' => $decoded ?? $responseBody, + ]; + } + + /** + * Extract plain text from a Responses API payload. + * + * @param array $response Result of LocalAIApi::createResponse|request. + * @return string + */ + public static function extractText(array $response): string + { + $payload = $response['data'] ?? $response; + if (!is_array($payload)) { + return ''; + } + + if (!empty($payload['output']) && is_array($payload['output'])) { + $combined = ''; + foreach ($payload['output'] as $item) { + if (!isset($item['content']) || !is_array($item['content'])) { + continue; + } + foreach ($item['content'] as $block) { + if (is_array($block) && ($block['type'] ?? '') === 'output_text' && !empty($block['text'])) { + $combined .= $block['text']; + } + } + } + if ($combined !== '') { + return $combined; + } + } + + if (!empty($payload['choices'][0]['message']['content'])) { + return (string) $payload['choices'][0]['message']['content']; + } + + return ''; + } + + /** + * Attempt to decode JSON emitted by the model (handles markdown fences). + * + * @param array $response + * @return array|null + */ + public static function decodeJsonFromResponse(array $response): ?array + { + $text = self::extractText($response); + if ($text === '') { + return null; + } + + $decoded = json_decode($text, true); + if (is_array($decoded)) { + return $decoded; + } + + $stripped = preg_replace('/^```json|```$/m', '', trim($text)); + if ($stripped !== null && $stripped !== $text) { + $decoded = json_decode($stripped, true); + if (is_array($decoded)) { + return $decoded; + } + } + + return null; + } + + /** + * Load configuration from ai/config.php. + * + * @return array + */ + private static function config(): array + { + if (self::$configCache === null) { + $configPath = __DIR__ . '/config.php'; + if (!file_exists($configPath)) { + throw new RuntimeException('AI config file not found: ai/config.php'); + } + $cfg = require $configPath; + if (!is_array($cfg)) { + throw new RuntimeException('Invalid AI config format: expected array'); + } + self::$configCache = $cfg; + } + + return self::$configCache; + } + + /** + * Build an absolute URL from base_url and a path. + */ + private static function buildUrl(string $path, string $baseUrl): string + { + $trimmed = trim($path); + if ($trimmed === '') { + return $baseUrl; + } + if (str_starts_with($trimmed, 'http://') || str_starts_with($trimmed, 'https://')) { + return $trimmed; + } + if ($trimmed[0] === '/') { + return $baseUrl . $trimmed; + } + return $baseUrl . '/' . $trimmed; + } +} + +// Legacy alias for backward compatibility with the previous class name. +if (!class_exists('OpenAIService')) { + class_alias(LocalAIApi::class, 'OpenAIService'); +} diff --git a/ai/config.php b/ai/config.php new file mode 100644 index 0000000..1ba1596 --- /dev/null +++ b/ai/config.php @@ -0,0 +1,52 @@ + $baseUrl, + 'responses_path' => $responsesPath, + 'project_id' => $projectId, + 'project_uuid' => $projectUuid, + 'project_header' => 'project-uuid', + 'default_model' => 'gpt-5', + 'timeout' => 30, + 'verify_tls' => true, +]; diff --git a/assets/css/custom.css b/assets/css/custom.css new file mode 100644 index 0000000..5da63cc --- /dev/null +++ b/assets/css/custom.css @@ -0,0 +1,36 @@ + +body { + font-family: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif; + background-color: #F8F9FA; + color: #212529; +} + +.hero { + background: linear-gradient(45deg, rgba(0, 87, 255, 0.1), rgba(76, 201, 240, 0.1)); + padding: 6rem 0; +} + +.btn-primary { + background-color: #0057FF; + border-color: #0057FF; + border-radius: 0.5rem; + padding: 0.75rem 1.5rem; +} + +.btn-secondary { + background-color: #FFFFFF; + border-color: #0057FF; + color: #0057FF; + border-radius: 0.5rem; + padding: 0.75rem 1.5rem; +} + +.section { + padding: 4rem 0; +} + +.card { + border: none; + border-radius: 0.5rem; + box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); +} diff --git a/assets/js/main.js b/assets/js/main.js new file mode 100644 index 0000000..0e5a919 --- /dev/null +++ b/assets/js/main.js @@ -0,0 +1,2 @@ + +// Future JavaScript will go here. diff --git a/assets/pasted-20251114-095035-cf5716ad.png b/assets/pasted-20251114-095035-cf5716ad.png new file mode 100644 index 0000000..19678fc Binary files /dev/null and b/assets/pasted-20251114-095035-cf5716ad.png differ diff --git a/contact.php b/contact.php new file mode 100644 index 0000000..140ccf2 --- /dev/null +++ b/contact.php @@ -0,0 +1,106 @@ + + + + + + + Contact Us - Kotkakey + + + + + + +
+ +
+ +
+
+
+
+
+
+

Contact Us

+

Have a question or want to learn more? Fill out the form below and we'll get back to you shortly.

+ + +
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ +
+
+
+
+
+
+
+
+ + + + + + + diff --git a/create-pool.php b/create-pool.php new file mode 100644 index 0000000..b8746ac --- /dev/null +++ b/create-pool.php @@ -0,0 +1,197 @@ +prepare("SELECT * FROM users WHERE id = ?"); +$stmt->execute([$userId]); +$user = $stmt->fetch(); + +// Handle form submission +if ($_SERVER['REQUEST_METHOD'] === 'POST') { + $medicineName = trim($_POST['medicine_name']); + $quantity = filter_input(INPUT_POST, 'quantity', FILTER_VALIDATE_INT); + $description = trim($_POST['description']); + + if (!empty($medicineName) && $quantity > 0) { + $sql = "INSERT INTO pooled_requests (user_id, medicine_name, status, participants) VALUES (?, ?, 'Pending', 1)"; + $stmt = $pdo->prepare($sql); + if ($stmt->execute([$userId, $medicineName])) { + header("Location: pooled-requests.php?success=1"); + exit; + } else { + $error = "Failed to create pool. Please try again."; + } + } else { + $error = "Medicine name and a valid quantity are required."; + } +} + +?> + + + + + + Create New Pool - Kotkakey + + + + + + + + + + + + + + + +
+ +
+ +
+ +

Create New Pooled Request

+ + +
+ + +
+
+
+ + +
+
+ + +
+
+ + +
+ + Cancel +
+
+
+ + + + + diff --git a/dashboard.php b/dashboard.php new file mode 100644 index 0000000..bb287b4 --- /dev/null +++ b/dashboard.php @@ -0,0 +1,337 @@ +prepare("SELECT * FROM users WHERE id = ?"); +$stmt->execute([$userId]); +$user = $stmt->fetch(); + +// Fetch pooled requests +$stmt = $pdo->prepare("SELECT * FROM pooled_requests WHERE user_id = ? ORDER BY created_at DESC"); +$stmt->execute([$userId]); +$pooled_requests = $stmt->fetchAll(); + +// Fetch shortage predictions +$stmt = $pdo->prepare("SELECT * FROM shortage_predictions WHERE user_id = ? ORDER BY days_to_shortage ASC"); +$stmt->execute([$userId]); +$predictions = $stmt->fetchAll(); + +// Prepare data for the chart +$prediction_labels = []; +$prediction_data = []; +foreach ($predictions as $prediction) { + $prediction_labels[] = $prediction['medicine_name']; + $prediction_data[] = $prediction['days_to_shortage']; +} + +// Calculate stats +$high_risk_alerts = 0; +foreach ($predictions as $prediction) { + if ($prediction['days_to_shortage'] < 20) { + $high_risk_alerts++; + } +} +$active_pooled_requests = count($pooled_requests); +$medicines_monitored = count($predictions); + +?> + + + + + + Pharmacy Dashboard - Kotkakey + + + + + + + + + + + + + + + +
+ +
+ +
+

Dashboard

+ +
+
+
+
+
+ +
+
+
High-Risk Alerts
+

+
+
+
+
+
+
+
+
+ +
+
+
Active Pooled Requests
+

+
+
+
+
+
+
+
+
+ +
+
+
Medicines Monitored
+

+
+
+
+
+
+ +
+
+
+

+ My Pooled Requests +

+ + + + + + + + + + + + + + + + + + + + + +
MedicineStatusParticipantsCreated
PharmaciesView
+
+
+
+
+

+ Shortage Predictions +

+ +
+
+
+ +
+ + + + + + + \ No newline at end of file diff --git a/index.php b/index.php index 7205f3d..a846ce8 100644 --- a/index.php +++ b/index.php @@ -1,150 +1,176 @@ - - + - - - New Style - - - - - - - - - - - - - - - - - - - + + + Kotkakey – Predicting and Preventing Medicine Shortages in Finland + + + + + + + + + + -
-
-

Analyzing your requirements and generating your website…

-
- Loading… -
-

AI is collecting your requirements and applying the first changes.

-

This page will update automatically as the plan is implemented.

-

Runtime: PHP — UTC

-
-
-
- Page updated: (UTC) -
+ +
+ +
+ +
+
+
+

Predict. Prevent. Supply.

+

Kotkakey uses data and AI to predict medicine shortages, reduce waste, and keep essential medicines available across Finland.

+ +
+
+ +
+
+
+
+

The Problem

+

In smaller countries like Finland, medicines often run out or expire because these markets are less profitable and get lower supply priority from pharma companies and wholesalers.

+

This creates shortages, waste, and financial losses for pharmacies.

+
+
+ Medicine Shortage Graphic +
+
+
+
+ +
+
+
+

Our Solution

+

Kotkakey uses AI and data analytics to create a smarter, more resilient supply chain.

+
+
+
+
+

Predict

+

Predict which medicines are likely to run out.

+
+
+
+
+

Pool

+

Pool pharmacy orders to increase buying power and attract supplier attention.

+
+
+
+
+

Provide

+

Identify expiring or surplus stock for redistribution.

+
+
+
+
+
+ +
+
+

Value Proposition

+
+
+
+
For Pharmacies
+

Early alerts, smarter purchasing, and reduced waste.

+
+
+
+
+
For Wholesalers
+

Better forecasting and logistics efficiency.

+
+
+
+
+
For the Healthcare System
+

More stable medicine availability for everyone.

+
+
+
+
+
+ +
+
+

Business Model

+
+
+
+
Subscription Access
+

Subscription-based access to the prediction dashboard.

+
+
+
+
+
Transaction Fees
+

A small transaction fee for verified cross-border or redistribution trades.

+
+
+
+
+
Data Insights
+

Data insights licensing for healthcare agencies and partners.

+
+
+
+
+
+ +
+
+
+
+

About Us

+

“Kotkakey was founded in Finland to solve a growing problem: when medicine runs short, patients and pharmacies pay the price. We combine science, data, and collaboration to make the system smarter — starting here in Finland.”

+
+
+
+
+ +
+
+

Interested in joining our pilot program or partnering with us?

+

Let’s connect.

+ +
+
+
+ + + + + - + \ No newline at end of file diff --git a/join-pool.php b/join-pool.php new file mode 100644 index 0000000..112da74 --- /dev/null +++ b/join-pool.php @@ -0,0 +1,201 @@ +prepare("SELECT * FROM users WHERE id = ?"); +$stmt->execute([$userId]); +$user = $stmt->fetch(); + +// Fetch pooled request details +$stmt = $pdo->prepare("SELECT pr.*, u.name as creator_name FROM pooled_requests pr JOIN users u ON pr.user_id = u.id WHERE pr.id = ?"); +$stmt->execute([$requestId]); +$request = $stmt->fetch(); + +if (!$request) { + header("Location: pooled-requests.php"); + exit; +} + +?> + + + + + + Join Pool - <?php echo htmlspecialchars($request['medicine_name']); ?> - Kotkakey + + + + + + + + + + + + + + + +
+ +
+ +
+ +

Pooled Request Details

+ +
+

+

Created by on

+ +
+
+
Status
+

+
+
+
Participants
+

Pharmacies

+
+
+
Required Quantity
+

100 Units

+
+
+ +
+
Description
+

This is a placeholder description for the pooled request of . Details about the request, required quantity, and other relevant information will be displayed here.

+
+ + +
+ +
+ + + + + diff --git a/login.php b/login.php new file mode 100644 index 0000000..e8ebd26 --- /dev/null +++ b/login.php @@ -0,0 +1,91 @@ +prepare("SELECT * FROM users WHERE email = ?"); + $stmt->execute([$email]); + $user = $stmt->fetch(); + + if ($user && password_verify($password, $user['password'])) { + $_SESSION['user_id'] = $user['id']; + header("Location: dashboard.php"); + exit; + } else { + $error_message = "Invalid email or password."; + } + } catch (PDOException $e) { + $error_message = "Database error: " . $e->getMessage(); + } + } +} +?> + + + + + + Login – Kotkakey + + + + + +
+ +
+ +
+
+
+
+
+

Login

+ +
+ +
+
+ + +
+
+ + +
+ +
+
+
+
+
+
+ + + + + + diff --git a/logout.php b/logout.php new file mode 100644 index 0000000..766a593 --- /dev/null +++ b/logout.php @@ -0,0 +1,6 @@ +prepare("SELECT * FROM users WHERE id = ?"); +$stmt->execute([$userId]); +$user = $stmt->fetch(); + +// Fetch all pooled requests +$stmt = $pdo->prepare("SELECT pr.*, u.name as creator_name FROM pooled_requests pr JOIN users u ON pr.user_id = u.id ORDER BY pr.created_at DESC"); +$stmt->execute(); +$all_requests = $stmt->fetchAll(); + +?> + + + + + + Pooled Requests - Kotkakey + + + + + + + + + + + + + + + +
+ +
+ +
+
+

All Pooled Requests

+ Create New Pool +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + +
MedicineStatusParticipantsCreated ByCreated On
PharmaciesView & Join
+
+
+ + + + + diff --git a/predictions.php b/predictions.php new file mode 100644 index 0000000..d3ef004 --- /dev/null +++ b/predictions.php @@ -0,0 +1,210 @@ +prepare("SELECT * FROM users WHERE id = ?"); +$stmt->execute([$userId]); +$user = $stmt->fetch(); + +// Fetch shortage predictions +$stmt = $pdo->prepare("SELECT * FROM shortage_predictions WHERE user_id = ? ORDER BY days_to_shortage ASC"); +$stmt->execute([$userId]); +$predictions = $stmt->fetchAll(); + +// Prepare data for the chart +$prediction_labels = []; +$prediction_data = []; +foreach ($predictions as $prediction) { + $prediction_labels[] = $prediction['medicine_name']; + $prediction_data[] = $prediction['days_to_shortage']; +} + +?> + + + + + + Shortage Predictions - Kotkakey + + + + + + + + + + + + + + + +
+ +
+ +
+

Shortage Predictions

+ +
+ +
+
+ + + + + + + diff --git a/profile.php b/profile.php new file mode 100644 index 0000000..199d443 --- /dev/null +++ b/profile.php @@ -0,0 +1,214 @@ +prepare("SELECT * FROM users WHERE id = ?"); +$stmt->execute([$userId]); +$user = $stmt->fetch(); + +// Handle profile update +if ($_SERVER['REQUEST_METHOD'] === 'POST') { + $name = trim($_POST['name']); + $email = trim($_POST['email']); + $password = $_POST['password']; + + // Basic validation + if (!empty($name) && !empty($email)) { + $sql = "UPDATE users SET name = ?, email = ? WHERE id = ?"; + $params = [$name, $email, $userId]; + + if (!empty($password)) { + $hashedPassword = password_hash($password, PASSWORD_DEFAULT); + $sql = "UPDATE users SET name = ?, email = ?, password = ? WHERE id = ?"; + $params = [$name, $email, $hashedPassword, $userId]; + } + + $updateStmt = $pdo->prepare($sql); + if ($updateStmt->execute($params)) { + // Refresh user data + header("Location: profile.php?success=1"); + exit; + } else { + $error = "Failed to update profile. Please try again."; + } + } else { + $error = "Name and Email are required."; + } +} + +// Refetch user data after potential update +$stmt = $pdo->prepare("SELECT * FROM users WHERE id = ?"); +$stmt->execute([$userId]); +$user = $stmt->fetch(); + +?> + + + + + + User Profile - Kotkakey + + + + + + + + + + + + + + + +
+ +
+ +
+

User Profile

+ + +
Profile updated successfully!
+ + +
+ + +
+
+
+ + +
+
+ + +
+
+ + + Leave blank to keep your current password. +
+ +
+
+
+ + + + + diff --git a/settings.php b/settings.php new file mode 100644 index 0000000..5e6f23b --- /dev/null +++ b/settings.php @@ -0,0 +1,186 @@ +prepare("SELECT * FROM users WHERE id = ?"); +$stmt->execute([$userId]); +$user = $stmt->fetch(); + +?> + + + + + + Settings - Kotkakey + + + + + + + + + + + + + + + +
+ +
+ +
+

Settings

+ +
+
+
Account Settings
+
+
+

Manage your account details.

+ +
+
+ + +
+
+ + +
+ +
+
+
+ +
+
+
Notification Settings
+
+
+

Choose how you receive notifications.

+ +
+ + +
+
+ + +
+
+
+ +
+ + + + + diff --git a/shortage-alerts.php b/shortage-alerts.php new file mode 100644 index 0000000..edab4d8 --- /dev/null +++ b/shortage-alerts.php @@ -0,0 +1,229 @@ +prepare("SELECT * FROM users WHERE id = ?"); +$stmt->execute([$userId]); +$user = $stmt->fetch(); + +// Fetch shortage alerts +$stmt = $pdo->prepare("SELECT * FROM shortage_predictions WHERE user_id = ? ORDER BY days_to_shortage ASC"); +$stmt->execute([$userId]); +$alerts = $stmt->fetchAll(); + +?> + + + + + + Shortage Alerts - Kotkakey + + + + + + + + + + + + + + + +
+ +
+ +
+

Shortage Alerts

+ +
+
+

All Alerts

+
+ + +
+
+ + + + + + + + + + + + + + + + + + + + + +
MedicineDays to ShortageRisk LevelLast UpdatedActions
+ $risk"; + ?> + + View Details +
+
+
+ + + + + + diff --git a/signup-thank-you.php b/signup-thank-you.php new file mode 100644 index 0000000..0997ad9 --- /dev/null +++ b/signup-thank-you.php @@ -0,0 +1,27 @@ + + +
+
+
+
+
+

Thank You!

+

Your application to join the pilot program has been received.

+

We appreciate your interest in helping us solve medicine shortages. Our team will review your information and contact you shortly with the next steps.

+
+ Return to Homepage +
+
+
+
+
+ + diff --git a/signup.php b/signup.php new file mode 100644 index 0000000..fb85424 --- /dev/null +++ b/signup.php @@ -0,0 +1,187 @@ +New Pilot Program Signup"; + $html_content .= "
    "; + $html_content .= "
  • Organization: " . htmlspecialchars($organization) . "
  • "; + $html_content .= "
  • Role: " . htmlspecialchars($role) . "
  • "; + $html_content .= "
  • Contact Person: " . htmlspecialchars($contact_person) . "
  • "; + $html_content .= "
  • Email: " . htmlspecialchars($email) . "
  • "; + $html_content .= "
  • Phone: " . htmlspecialchars($phone) . "
  • "; + $html_content .= "
  • Address / Region: " . htmlspecialchars($address) . "
  • "; + $html_content .= "
  • Patients Served: " . htmlspecialchars($patients_served) . "
  • "; + $html_content .= "
  • Main Challenges:
    " . nl2br(htmlspecialchars($challenges)) . "
  • "; + $html_content .= "
"; + + $text_content = "New Pilot Program Signup + +"; + $text_content .= "Organization: " . $organization . " +"; + $text_content .= "Role: " . $role . " +"; + $text_content .= "Contact Person: " . $contact_person . " +"; + $text_content .= "Email: " . $email . " +"; + $text_content .= "Phone: " . $phone . " +"; + $text_content .= "Address / Region: " . $address . " +"; + $text_content .= "Patients Served: " . $patients_served . " +"; + $text_content .= "Main Challenges: +" . $challenges . " +"; + + // Use the generic sendMail function + $result = MailService::sendMail($to, $subject, $html_content, $text_content, ['reply_to' => $email]); + + if (!empty($result['success'])) { + header('Location: signup-thank-you.php'); + exit; + } else { + // Log error, maybe set a generic error message for the user + error_log('MailService Error: ' . ($result['error'] ?? 'Unknown error')); + $errors['submit'] = 'Sorry, there was a problem sending your application. Please try again later.'; + } + } +} + +// Include header +include __DIR__ . '/index.php'; +?> + +
+
+
+
+
+

Join the Pilot Program

+

Become a part of the solution to medicine shortages. Fill out the form below to apply for the Kotkakey pilot program.

+ + +
+ + +
+
+ + +
+
+ +
+ + +
+
+ +
+ + +
+
+ +
+ + +
+
+ +
+ + +
+
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+
+ +
+ +
+
+
+
+
+
+
+ + diff --git a/thank-you.php b/thank-you.php new file mode 100644 index 0000000..761b97e --- /dev/null +++ b/thank-you.php @@ -0,0 +1,52 @@ + + + + + + Thank You - Kotkakey + + + + + + +
+ +
+ +
+
+
+
+
+
+

Thank You!

+

Your message has been sent successfully. We will get back to you as soon as possible.

+ Return to Homepage +
+
+
+
+
+
+ + + + + +