modify("-$paymentCycleDays days"); $totalCycleDays = $lastPaymentDate->diff($nextPaymentDate)->days; $daysSinceLastPayment = $lastPaymentDate->diff($currentDate)->days; $subscriptionProgress = 0; if ($totalCycleDays > 0) { $subscriptionProgress = ($daysSinceLastPayment / $totalCycleDays) * 100; } return floor($subscriptionProgress); } function getPricePerMonth($cycle, $frequency, $price) { switch ($cycle) { case 1: $numberOfPaymentsPerMonth = (30 / $frequency); return $price * $numberOfPaymentsPerMonth; case 2: $numberOfPaymentsPerMonth = (4.35 / $frequency); return $price * $numberOfPaymentsPerMonth; case 3: $numberOfPaymentsPerMonth = (1 / $frequency); return $price * $numberOfPaymentsPerMonth; case 4: $numberOfMonths = (12 * $frequency); return $price / $numberOfMonths; case 5: return 0; } } function getPriceConverted($price, $currency, $database) { $query = "SELECT rate FROM currencies WHERE id = :currency"; $stmt = $database->prepare($query); $stmt->bindParam(':currency', $currency, SQLITE3_INTEGER); $result = $stmt->execute(); $exchangeRate = $result->fetchArray(SQLITE3_ASSOC); if ($exchangeRate === false) { return $price; } else { $fromRate = $exchangeRate['rate']; return $price / $fromRate; } } function formatPrice($price, $currencyCode, $currencies) { $formattedPrice = CurrencyFormatter::format($price, $currencyCode); if (strstr($formattedPrice, $currencyCode)) { $symbol = $currencyCode; foreach ($currencies as $currency) { if ($currency['code'] === $currencyCode) { if ($currency['symbol'] != "") { $symbol = $currency['symbol']; } break; } } $formattedPrice = str_replace($currencyCode, $symbol, $formattedPrice); } return $formattedPrice; } function formatDate($date, $lang = 'en') { $currentYear = date('Y'); $dateYear = date('Y', strtotime($date)); // Determine the date format based on whether the year matches the current year $dateFormat = ($currentYear == $dateYear) ? 'MMM d' : 'MMM yyyy'; // Try to create an IntlDateFormatter; if it fails, fallback to 'en' try { $formatter = new IntlDateFormatter( $lang, IntlDateFormatter::SHORT, IntlDateFormatter::NONE, null, null, $dateFormat ); if (!$formatter) { throw new Exception('Failed to create IntlDateFormatter with language: ' . $lang); } } catch (Throwable $e) { $lang = 'en'; // Fallback to English on error $formatter = new IntlDateFormatter( $lang, IntlDateFormatter::SHORT, IntlDateFormatter::NONE, null, null, $dateFormat ); } // Format the date $formattedDate = $formatter->format(new DateTime($date)); return $formattedDate; } function printSubscriptions($subscriptions, $sort, $categories, $members, $i18n, $colorTheme, $imagePath, $disabledToBottom, $mobileNavigation, $showSubscriptionProgress, $currencies, $lang) { if ($sort === "price") { usort($subscriptions, function ($a, $b) { return $a['price'] < $b['price'] ? 1 : -1; }); if ($disabledToBottom === 'true') { usort($subscriptions, function ($a, $b) { return $a['inactive'] - $b['inactive']; }); } } // One-time purchases always go to the bottom regardless of sort order usort($subscriptions, fn($a, $b) => ($a['one_time'] ? 1 : 0) - ($b['one_time'] ? 1 : 0)); $currentCategory = 0; $currentPayerUserId = 0; $currentPaymentMethodId = 0; $oneTimeSectionShown = false; foreach ($subscriptions as $subscription) { if ($subscription['one_time'] && !$oneTimeSectionShown) { ?>