File manager - Edit - /home/cipherteam/htdocs/cipherteam.in/API/Finance/IPOSubscription/chitto_subscription.php
Back
<?php // ==================================================================== // chitto_subscription.php — Live IPO subscription tracker // Fetches https://www.chittorgarh.net/documents/subscription/{id}/subscriptions.html // and renders it using the Market Intel design system (per design.md). // // URL params: // ?ipo=<chittorgarh_id> IPO numeric ID, e.g. 3090 for Bagmane REIT // ?c=<6-hex> Optional accent color (defaults to #112D4E) // ==================================================================== // ---------------- Inputs ---------------- $ipoId = (isset($_GET['ipo']) && is_numeric($_GET['ipo'])) ? (int)$_GET['ipo'] : 0; // Color resolution per design.md §10 if (isset($_GET['c'])) { $clean = preg_replace('/[^0-9a-fA-F]/', '', $_GET['c']); $color = (strlen($clean) === 6) ? '#' . strtolower($clean) : '#112D4E'; } else { $color = '#112D4E'; } function tintColor($hex, $percent) { $hex = ltrim($hex, '#'); if (strlen($hex) === 3) $hex = $hex[0].$hex[0].$hex[1].$hex[1].$hex[2].$hex[2]; $r = hexdec(substr($hex, 0, 2)); $g = hexdec(substr($hex, 2, 2)); $b = hexdec(substr($hex, 4, 2)); $r = (int)($r + (255 - $r) * $percent); $g = (int)($g + (255 - $g) * $percent); $b = (int)($b + (255 - $b) * $percent); return sprintf("#%02x%02x%02x", $r, $g, $b); } function shadeColor($hex, $percent) { $hex = ltrim($hex, '#'); if (strlen($hex) === 3) $hex = $hex[0].$hex[0].$hex[1].$hex[1].$hex[2].$hex[2]; $r = hexdec(substr($hex, 0, 2)); $g = hexdec(substr($hex, 2, 2)); $b = hexdec(substr($hex, 4, 2)); $r = (int)($r * (1 - $percent)); $g = (int)($g * (1 - $percent)); $b = (int)($b * (1 - $percent)); return sprintf("#%02x%02x%02x", $r, $g, $b); } $colorPageBg = tintColor($color, 0.93); $colorSoft = tintColor($color, 0.86); $colorSofter = tintColor($color, 0.92); $colorLight = tintColor($color, 0.62); $colorHair = tintColor($color, 0.82); $colorDark = shadeColor($color, 0.45); $colorDeep = shadeColor($color, 0.65); $colorDarkest = shadeColor($color, 0.82); // ---------------- State to fill from the fetch ---------------- $ipoName = ''; $updatedAt = ''; // e.g. "May 7, 2026 12:19:42 PM" $dayLabel = ''; // e.g. "Day 3" $totalTimes = null; // float, e.g. 5.56 $totalApps = ''; // e.g. "1,10,591" $mainRows = []; // [['category','times_str','offered','bid_for','amount'], ...] $dayCols = []; // header columns after "Date" $dayRows = []; // [['date'=>..., 'cols'=>[...]], ...] $fetchErr = ''; $fetchedOk = false; // ---------------- Helpers ---------------- function parseTimesNum($s) { // Extract a numeric value from strings like "1.97", "[.]", "0", "—" if ($s === null) return null; $s = trim((string)$s); if ($s === '' || $s === '—' || $s === '-' || strpos($s, '[.]') !== false) return null; if (!preg_match('/-?[\d]+(\.\d+)?/', $s, $m)) return null; return (float)$m[0]; } function fmtTimesStr($n) { if ($n === null) return '—'; return number_format($n, 2) . '×'; } // ---------------- Fetch ---------------- if ($ipoId > 0) { $url = 'https://www.chittorgarh.net/documents/subscription/' . $ipoId . '/subscriptions.html?abc=' . (time() % 1000); $ch = curl_init(); curl_setopt_array($ch, [ CURLOPT_URL => $url, CURLOPT_RETURNTRANSFER => true, CURLOPT_TIMEOUT => 10, CURLOPT_CONNECTTIMEOUT => 5, CURLOPT_FOLLOWLOCATION => true, CURLOPT_ENCODING => '', // accept gzip CURLOPT_HTTPHEADER => [ 'sec-ch-ua-platform: "Windows"', 'Cache-Control: no-store', 'Referer: https://www.chittorgarh.com/', 'Pragma: no-cache', 'sec-ch-ua: "Google Chrome";v="147", "Not.A/Brand";v="8", "Chromium";v="147"', 'sec-ch-ua-mobile: ?0', 'Expires: 0', 'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/147.0.0.0 Safari/537.36', ], ]); $raw = curl_exec($ch); $code = (int)curl_getinfo($ch, CURLINFO_HTTP_CODE); $cerr = curl_error($ch); curl_close($ch); if (!$raw || $code !== 200) { $fetchErr = $cerr ? $cerr : ('HTTP ' . $code); } else { $fetchedOk = true; // --- Parse with DOMDocument --- libxml_use_internal_errors(true); $doc = new DOMDocument(); // Wrap as full doc; tolerate fragment input $doc->loadHTML('<?xml encoding="UTF-8"?><html><body>' . $raw . '</body></html>'); libxml_clear_errors(); $xp = new DOMXPath($doc); // Headline: the <p> containing "subscribed ... times". Restrict to <p> // because the surrounding <div itemscope> wraps both the <h2> ("REIT // Subscription Status Live") AND this paragraph; its rolled-up // textContent would concatenate the H2 prefix onto the IPO name. $headline = ''; foreach ($xp->query('//p') as $node) { $t = trim(preg_replace('/\s+/', ' ', $node->textContent)); if ($t !== '' && stripos($t, 'subscribed') !== false && stripos($t, 'times') !== false) { $headline = $t; break; } } // Pull pieces from the headline if ($headline !== '') { // IPO name = text before " subscribed " if (preg_match('/^(.+?)\s+subscribed\b/i', $headline, $m)) { $ipoName = trim($m[1]); } // Total times = first "subscribed N.NN times" if (preg_match('/subscribed\s+([\d,.]+)\s+times/i', $headline, $m)) { $totalTimes = parseTimesNum($m[1]); } // Updated = "by Mon DD, YYYY HH:MM:SS AM/PM" if (preg_match('/by\s+([A-Z][a-z]+\s+\d{1,2},\s+\d{4}\s+[\d:]+\s+[AP]M)/', $headline, $m)) { $updatedAt = $m[1]; } // Day label = "(Day N)" if (preg_match('/\((Day\s*\d+)\)/i', $headline, $m)) { $dayLabel = $m[1]; } } // Tables — classify by header content foreach ($xp->query('//table') as $table) { $rows = []; foreach ($table->getElementsByTagName('tr') as $tr) { $cells = []; foreach ($tr->childNodes as $c) { if ($c->nodeType === XML_ELEMENT_NODE && ($c->nodeName === 'th' || $c->nodeName === 'td')) { $cells[] = trim(preg_replace('/\s+/', ' ', $c->textContent)); } } if (!empty($cells)) $rows[] = $cells; } if (count($rows) < 2) continue; $head = array_map('strtolower', $rows[0]); // Main subscription table: Category / Subscription / Shares Offered / Shares bid / Amount if (count($head) >= 4 && strpos($head[0], 'category') !== false && strpos($head[1], 'subscription') !== false ) { for ($i = 1; $i < count($rows); $i++) { $r = $rows[$i]; $mainRows[] = [ 'category' => trim(rtrim($r[0] ?? '', " *\t")), 'times' => $r[1] ?? '', 'offered' => $r[2] ?? '', 'bid_for' => $r[3] ?? '', 'amount' => $r[4] ?? '', ]; } } // Day-wise table: first column is "Date" elseif (count($head) >= 2 && strpos($head[0], 'date') !== false) { $dayCols = array_slice($rows[0], 1); for ($i = 1; $i < count($rows); $i++) { $r = $rows[$i]; $dayRows[] = [ 'date' => $r[0] ?? '', 'cols' => array_slice($r, 1), ]; } } } // Total Applications — anywhere on the page $bodyText = $doc->textContent; if (preg_match('/Total\s+Applications:\s*([\d,]+)/i', $bodyText, $m)) { $totalApps = trim($m[1]); } // If headline didn't yield a total, fall back to the "Total" row in mainRows if ($totalTimes === null) { foreach ($mainRows as $r) { if (stripos($r['category'], 'total') !== false) { $totalTimes = parseTimesNum($r['times']); break; } } } } } ?> <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width,initial-scale=1"> <title><?php echo $ipoName ? htmlspecialchars($ipoName) . ' — Live Subscription' : 'Live Subscription'; ?></title> <link rel="preconnect" href="https://fonts.googleapis.com"> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> <link href="https://fonts.googleapis.com/css2?family=Fraunces:opsz,ital,wght@9..144,0,400;9..144,0,500;9..144,0,600;9..144,0,700;9..144,1,400&family=DM+Sans:wght@400;500;600;700&family=JetBrains+Mono:wght@500;600;700&display=swap" rel="stylesheet"> <style> :root { --accent: <?php echo $color; ?>; --accent-deep: <?php echo $colorDeep; ?>; --accent-darkest:<?php echo $colorDarkest; ?>; --accent-dark: <?php echo $colorDark; ?>; --accent-light: <?php echo $colorLight; ?>; --accent-hair: <?php echo $colorHair; ?>; --accent-soft: <?php echo $colorSoft; ?>; --accent-softer: <?php echo $colorSofter; ?>; --page: <?php echo $colorPageBg; ?>; --surface: #ffffff; --ink: #1a1512; --ink-2: #4a4340; --ink-3: #7a746f; --buy: #0f6b3f; --buy-bg: #def0e5; --sell: #a81d25; --sell-bg: #fadee0; --radius: 16px; --radius-sm: 10px; --radius-pill: 999px; } * { box-sizing: border-box; margin: 0; padding: 0; } html, body { background: var(--page); background-image: radial-gradient(circle at 8% 0%, var(--accent-softer) 0%, transparent 38%), radial-gradient(circle at 100% 100%, var(--accent-soft) 0%, transparent 42%); background-attachment: fixed; } body { padding: 14px 12px 24px; min-height: 100vh; font-family: 'DM Sans', system-ui, sans-serif; font-size: 14px; line-height: 1.45; color: var(--ink); -webkit-font-smoothing: antialiased; } /* ----- Hero (dark gradient) ----- */ .hero { background: linear-gradient(135deg, var(--accent) 0%, var(--accent-deep) 100%); color: #fff; border-radius: var(--radius); padding: 18px 18px 16px; margin-bottom: 12px; position: relative; overflow: hidden; box-shadow: 0 14px 32px -14px <?php echo $color; ?>66; animation: slideUp .5s ease backwards; } .hero::before, .hero::after { content: ""; position: absolute; border-radius: 50%; pointer-events: none; } .hero::before { right: -20px; top: -20px; width: 80px; height: 80px; border: 1.5px solid rgba(255,255,255,0.18); } .hero::after { right: -55px; top: -55px; width: 140px; height: 140px; border: 1.5px solid rgba(255,255,255,0.10); } .hero__eyebrow { display: inline-flex; align-items: center; gap: 7px; font-size: 9px; font-weight: 700; letter-spacing: 0.18em; text-transform: uppercase; color: rgba(255,255,255,0.82); position: relative; z-index: 1; } .hero__eyebrow .sep { opacity: 0.55; margin: 0 2px; } .hero__pulse { display: inline-block; width: 7px; height: 7px; border-radius: 50%; background: #4ade80; box-shadow: 0 0 0 0 rgba(74,222,128,0.7); animation: pulse-green 1.8s ease-in-out infinite; } @keyframes pulse-green { 0% { box-shadow: 0 0 0 0 rgba(74,222,128,0.7); } 70% { box-shadow: 0 0 0 8px rgba(74,222,128,0); } 100% { box-shadow: 0 0 0 0 rgba(74,222,128,0); } } .hero__name { font-family: 'Fraunces', serif; font-weight: 500; font-size: 30px; line-height: 1.1; letter-spacing: -0.025em; color: #fff; margin-top: 8px; text-transform: uppercase; position: relative; z-index: 1; word-break: break-word; } .hero__divider { height: 1px; background: rgba(255,255,255,0.16); margin: 12px 0 10px; position: relative; z-index: 1; } .hero__row { display: flex; align-items: center; justify-content: space-between; gap: 10px; position: relative; z-index: 1; } .hero__updated { font-family: 'DM Sans', sans-serif; font-size: 9px; font-weight: 700; letter-spacing: 0.16em; text-transform: uppercase; color: rgba(255,255,255,0.72); flex: 1; min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .hero__refresh { display: inline-flex; align-items: center; gap: 6px; background: rgba(255,255,255,0.14); border: 1px solid rgba(255,255,255,0.28); color: #fff; font-family: 'DM Sans', sans-serif; font-size: 10px; font-weight: 700; letter-spacing: 0.12em; text-transform: uppercase; padding: 7px 12px 7px 11px; border-radius: var(--radius-pill); cursor: pointer; transition: background 0.15s, transform 0.4s; } .hero__refresh:hover { background: rgba(255,255,255,0.22); } .hero__refresh.spin svg { transform: rotate(360deg); } .hero__refresh svg { width: 11px; height: 11px; transition: transform 0.6s ease; } /* ----- Summary card ----- */ .summary-card { background: var(--surface); border: 1px solid var(--accent-hair); border-radius: var(--radius); padding: 14px 16px; margin-bottom: 12px; display: flex; align-items: stretch; gap: 14px; position: relative; overflow: hidden; box-shadow: 0 2px 0 <?php echo $color; ?>0d; animation: slideUp .5s ease backwards; animation-delay: 0.05s; } .summary-card::before { content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: 4px; background: var(--accent); } .summary-card__col { flex: 1; min-width: 0; } .summary-card__col + .summary-card__col { border-left: 1px dashed var(--accent-light); padding-left: 14px; } .summary-card__label { font-size: 9px; font-weight: 700; letter-spacing: 0.14em; text-transform: uppercase; color: var(--accent-dark); opacity: 0.85; margin-bottom: 6px; } .summary-card__value { font-family: 'Fraunces', serif; font-weight: 500; font-size: 32px; line-height: 1; letter-spacing: -0.025em; color: var(--accent-deep); } .summary-card__value--small { font-family: 'JetBrains Mono', monospace; font-weight: 600; font-size: 18px; letter-spacing: -0.01em; color: var(--ink); } .summary-card__sub { font-size: 11px; color: var(--ink-3); margin-top: 4px; } /* ----- Section title ----- */ .section-title { font-family: 'DM Sans', sans-serif; font-size: 9px; font-weight: 700; letter-spacing: 0.18em; text-transform: uppercase; color: var(--accent-dark); opacity: 0.85; margin: 14px 4px 8px; display: flex; align-items: center; gap: 8px; } .section-title::before, .section-title::after { content: ""; flex: 1; height: 1px; background: var(--accent-light); opacity: 0.5; } .section-title__text { white-space: nowrap; } /* ----- Per-category card ----- */ .cat-card { background: var(--surface); border: 1px solid var(--accent-hair); border-radius: var(--radius); padding: 12px 14px 11px; margin-bottom: 10px; position: relative; overflow: hidden; box-shadow: 0 2px 0 <?php echo $color; ?>0d; animation: slideUp .5s ease backwards; } .cat-card::before { content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: 4px; background: var(--buy); } .cat-card--low::before { background: var(--sell); } .cat-card--total { background: linear-gradient(135deg, var(--surface) 0%, var(--accent-softer) 100%); border-color: var(--accent-light); } .cat-card--total::before { background: var(--accent-deep); } .cat-card::after { content: ""; position: absolute; right: -28px; top: -28px; width: 70px; height: 70px; border-radius: 50%; background: var(--accent-softer); opacity: 0.55; pointer-events: none; } .cat-card__head { display: flex; align-items: center; justify-content: space-between; gap: 10px; position: relative; z-index: 1; } .cat-card__name { font-family: 'Fraunces', serif; font-weight: 500; font-size: 17px; letter-spacing: -0.015em; color: var(--accent-deep); flex: 1; min-width: 0; } .cat-card--total .cat-card__name { color: var(--accent-darkest); } .cat-card__times { font-family: 'JetBrains Mono', monospace; font-weight: 700; font-size: 18px; line-height: 1; letter-spacing: -0.02em; color: var(--buy); background: var(--buy-bg); border: 1px solid #b7dfc0; padding: 6px 10px; border-radius: var(--radius-pill); flex: 0 0 auto; } .cat-card--low .cat-card__times { color: var(--sell); background: var(--sell-bg); border-color: #f0b9bf; } .cat-card--total .cat-card__times { color: #fff; background: var(--accent-deep); border-color: var(--accent-deep); } .cat-card__bar { height: 3px; background: var(--accent-softer); border-radius: 2px; margin: 10px 0 11px; overflow: hidden; position: relative; z-index: 1; } .cat-card__bar-fill { height: 100%; background: var(--buy); border-radius: 2px; transition: width 0.5s cubic-bezier(.2,.8,.2,1); } .cat-card--low .cat-card__bar-fill { background: var(--sell); } .cat-card--total .cat-card__bar-fill { background: var(--accent-deep); } .cat-card__footer { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 8px; position: relative; z-index: 1; } .cat-card__stat { min-width: 0; position: relative; } .cat-card__stat + .cat-card__stat::before { content: ""; position: absolute; left: -4px; top: 18%; bottom: 18%; width: 1px; background: var(--accent-light); opacity: 0.55; } .cat-card__stat-label { font-size: 9px; font-weight: 700; letter-spacing: 0.10em; text-transform: uppercase; color: var(--accent-dark); opacity: 0.8; margin-bottom: 3px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .cat-card__stat-value { font-family: 'JetBrains Mono', monospace; font-weight: 600; font-size: 12.5px; line-height: 1.15; letter-spacing: -0.01em; color: var(--ink); word-break: break-word; } .cat-card__stat-unit { font-family: 'DM Sans', sans-serif; font-weight: 600; font-size: 10px; color: var(--ink-3); margin-left: 1px; } /* ----- Day-wise card ----- */ .dw-card { background: var(--surface); border: 1px solid var(--accent-hair); border-radius: var(--radius); margin-bottom: 12px; overflow: hidden; position: relative; box-shadow: 0 2px 0 <?php echo $color; ?>0d; animation: slideUp .5s ease backwards; } .dw-card::before { content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: 4px; background: var(--accent); z-index: 1; } .dw-card__head { padding: 12px 16px 10px; border-bottom: 1px solid var(--accent-hair); background: var(--accent-softer); } .dw-card__title { font-family: 'Fraunces', serif; font-weight: 500; font-size: 15px; letter-spacing: -0.015em; color: var(--accent-deep); } .dw-card__sub { font-size: 10px; color: var(--accent-dark); opacity: 0.85; margin-top: 2px; letter-spacing: 0.04em; } .dw-card__table { padding: 8px 4px 8px; } .dw-row { display: grid; gap: 4px; align-items: center; padding: 8px 12px; border-radius: 8px; } .dw-row + .dw-row { border-top: 1px dashed var(--accent-hair); } .dw-row--head { border-top: none !important; font-size: 9px; font-weight: 700; letter-spacing: 0.12em; text-transform: uppercase; color: var(--accent-dark); opacity: 0.85; padding: 6px 12px 8px; } .dw-row__date { font-family: 'DM Sans', sans-serif; font-size: 12px; font-weight: 600; color: var(--accent-deep); white-space: nowrap; } .dw-row--head .dw-row__date { color: var(--accent-dark); font-size: 9px; font-weight: 700; } .dw-row__col { font-family: 'JetBrains Mono', monospace; font-size: 13px; font-weight: 600; letter-spacing: -0.01em; text-align: right; color: var(--ink-2); } .dw-row--head .dw-row__col { font-family: 'DM Sans', sans-serif; font-size: 9px; font-weight: 700; letter-spacing: 0.10em; color: var(--accent-dark); } .dw-row__col--high { color: var(--buy); } .dw-row__col--low { color: var(--sell); opacity: 0.85; } /* ----- Empty state ----- */ .empty { background: var(--surface); border: 1px dashed var(--accent-light); border-radius: var(--radius); padding: 36px 22px; text-align: center; margin-bottom: 12px; animation: slideUp .5s ease backwards; } .empty__icon { width: 52px; height: 52px; margin: 0 auto 14px; border-radius: 50%; background: var(--accent); color: #fff; display: flex; align-items: center; justify-content: center; font-family: 'Fraunces', serif; font-size: 24px; font-style: italic; box-shadow: 0 6px 16px -4px <?php echo $color; ?>66; } .empty__text { font-family: 'Fraunces', serif; font-size: 17px; font-weight: 500; letter-spacing: -0.015em; color: var(--accent-deep); line-height: 1.3; } .empty__sub { margin-top: 6px; font-size: 12px; color: var(--ink-3); line-height: 1.5; } .empty__sub-tip { margin-top: 8px; font-size: 11px; color: var(--ink-3); opacity: 0.78; } /* ----- Disclaimer (foldable) ----- */ .disclaimer-fold { background: var(--surface); border: 1px solid var(--accent-hair); border-left: 3px solid var(--accent); border-radius: var(--radius-sm); margin-top: 14px; overflow: hidden; box-shadow: 0 1px 0 <?php echo $color; ?>0d; animation: slideUp .5s ease backwards; } .disclaimer-fold__head { width: 100%; background: transparent; border: none; padding: 11px 14px; display: flex; align-items: center; justify-content: space-between; cursor: pointer; font-family: 'DM Sans', sans-serif; } .disclaimer-fold__label { font-size: 9px; font-weight: 700; letter-spacing: 0.14em; text-transform: uppercase; color: var(--accent); } .disclaimer-fold__chev { width: 10px; height: 10px; color: var(--accent); transition: transform 0.25s ease; } .disclaimer-fold.open .disclaimer-fold__chev { transform: rotate(180deg); } .disclaimer-fold__body { max-height: 0; overflow: hidden; transition: max-height 0.3s ease; } .disclaimer-fold.open .disclaimer-fold__body { max-height: 600px; } .disclaimer-fold__inner { padding: 0 14px 12px; font-size: 11.5px; line-height: 1.55; color: var(--ink-2); } .disclaimer-fold__inner p + p { margin-top: 6px; } @keyframes slideUp { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } } </style> </head> <body> <?php if ($ipoId <= 0): ?> <!-- No IPO ID provided --> <div class="empty"> <div class="empty__icon">i</div> <div class="empty__text">No IPO selected</div> <div class="empty__sub">Add <code>?ipo=<id></code> to the URL to view live subscription data.</div> <div class="empty__sub-tip">Example: <code>?ipo=3090</code></div> </div> <?php elseif ($fetchErr !== ''): ?> <!-- Fetch error --> <div class="empty"> <div class="empty__icon"><svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><line x1="12" y1="9" x2="12" y2="13"/><line x1="12" y1="17" x2="12.01" y2="17"/><circle cx="12" cy="12" r="10"/></svg></div> <div class="empty__text">Could not load subscription</div> <div class="empty__sub"><?php echo htmlspecialchars($fetchErr); ?></div> <div class="empty__sub-tip">Will retry automatically. Tap below to refresh now.</div> <div style="margin-top:14px;"> <button onclick="window.location.reload()" style="background:var(--accent);color:#fff;border:none;padding:9px 18px;border-radius:var(--radius-pill);font-size:10px;font-weight:700;letter-spacing:0.12em;text-transform:uppercase;cursor:pointer;font-family:'DM Sans',sans-serif;">Retry now</button> </div> </div> <?php elseif (empty($mainRows)): ?> <!-- Fetched OK but no parsable data --> <div class="empty"> <div class="empty__icon">i</div> <div class="empty__text">Subscription not yet available</div> <div class="empty__sub">Bidding may not have started yet, or the registrar has not published any data.</div> <div class="empty__sub-tip">This page will refresh automatically.</div> </div> <?php else: ?> <!-- ===== HERO ===== --> <section class="hero"> <div class="hero__eyebrow"> <span class="hero__pulse"></span> LIVE SUBSCRIPTION <?php if ($dayLabel !== ''): ?><span class="sep">·</span> <?php echo strtoupper(htmlspecialchars($dayLabel)); ?><?php endif; ?> </div> <h1 class="hero__name"><?php echo htmlspecialchars($ipoName !== '' ? $ipoName : 'IPO'); ?></h1> <div class="hero__divider"></div> <div class="hero__row"> <div class="hero__updated"> <?php if ($updatedAt !== ''): ?> Updated <?php echo htmlspecialchars($updatedAt); ?> <?php else: ?> Live data <?php endif; ?> </div> <button class="hero__refresh" onclick="this.classList.add('spin'); window.location.reload();" type="button"> <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><polyline points="23 4 23 10 17 10"/><polyline points="1 20 1 14 7 14"/><path d="M3.51 9a9 9 0 0 1 14.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0 0 20.49 15"/></svg> Refresh </button> </div> </section> <!-- ===== SUMMARY ===== --> <div class="summary-card"> <div class="summary-card__col"> <div class="summary-card__label">Total Subscription</div> <div class="summary-card__value"><?php echo fmtTimesStr($totalTimes); ?></div> <?php if ($totalTimes !== null): ?> <div class="summary-card__sub"> <?php if ($totalTimes >= 1) { echo 'Issue is fully subscribed'; } else { echo 'Issue is undersubscribed'; } ?> </div> <?php endif; ?> </div> <?php if ($totalApps !== ''): ?> <div class="summary-card__col"> <div class="summary-card__label">Total Applications</div> <div class="summary-card__value summary-card__value--small"><?php echo htmlspecialchars($totalApps); ?></div> <div class="summary-card__sub">Bids received so far</div> </div> <?php endif; ?> </div> <!-- ===== CATEGORY BREAKDOWN ===== --> <div class="section-title"><span class="section-title__text">Category Breakdown</span></div> <?php // Re-order: put "Total" row last (Chittorgarh already does this, but be defensive) $ordered = []; $totalRow = null; foreach ($mainRows as $r) { if (stripos($r['category'], 'total') !== false) { $totalRow = $r; } else { $ordered[] = $r; } } if ($totalRow) $ordered[] = $totalRow; foreach ($ordered as $i => $row): $isTotal = stripos($row['category'], 'total') !== false; $timesNum = parseTimesNum($row['times']); $isLow = ($timesNum !== null && $timesNum < 1 && !$isTotal); $fillPct = ($timesNum !== null) ? min(100, $timesNum * 100) : 0; $delay = number_format(min(0.10 + $i * 0.04, 0.7), 2); // Hide amount column if it's "0" or empty (e.g., Anchor row often has 0 amount) $showAmount = $row['amount'] !== '' && $row['amount'] !== '0' && $row['amount'] !== '-' && $row['amount'] !== '—'; ?> <article class="cat-card<?php echo $isLow ? ' cat-card--low' : ''; echo $isTotal ? ' cat-card--total' : ''; ?>" style="animation-delay: <?php echo $delay; ?>s"> <div class="cat-card__head"> <div class="cat-card__name"><?php echo htmlspecialchars($row['category']); ?></div> <div class="cat-card__times"><?php echo fmtTimesStr($timesNum); ?></div> </div> <div class="cat-card__bar"><div class="cat-card__bar-fill" style="width: <?php echo $fillPct; ?>%"></div></div> <div class="cat-card__footer"> <div class="cat-card__stat"> <div class="cat-card__stat-label">Shares Offered</div> <div class="cat-card__stat-value"><?php echo htmlspecialchars($row['offered'] !== '' ? $row['offered'] : '—'); ?></div> </div> <div class="cat-card__stat"> <div class="cat-card__stat-label">Shares Bid For</div> <div class="cat-card__stat-value"><?php echo htmlspecialchars($row['bid_for'] !== '' ? $row['bid_for'] : '—'); ?></div> </div> <div class="cat-card__stat"> <div class="cat-card__stat-label">Total Amount</div> <div class="cat-card__stat-value"> <?php if ($showAmount): ?> ₹<?php echo htmlspecialchars($row['amount']); ?><span class="cat-card__stat-unit"> Cr</span> <?php else: ?> — <?php endif; ?> </div> </div> </div> </article> <?php endforeach; ?> <?php if (!empty($dayRows)): ?> <!-- ===== DAY-WISE ===== --> <div class="section-title"><span class="section-title__text">Day-wise Progress</span></div> <?php // Build grid template: 1.4fr for date column + 1fr per data column $colCount = count($dayCols); $gridStyle = '1.5fr ' . str_repeat('1fr ', $colCount); ?> <div class="dw-card" style="animation-delay: 0.18s"> <div class="dw-card__head"> <div class="dw-card__title">Subscription times by day</div> <div class="dw-card__sub"><?php echo $colCount; ?> categor<?php echo $colCount === 1 ? 'y' : 'ies'; ?> tracked</div> </div> <div class="dw-card__table"> <div class="dw-row dw-row--head" style="grid-template-columns: <?php echo trim($gridStyle); ?>"> <div class="dw-row__date">Date</div> <?php foreach ($dayCols as $col): ?> <div class="dw-row__col"><?php echo htmlspecialchars($col); ?></div> <?php endforeach; ?> </div> <?php foreach ($dayRows as $row): ?> <div class="dw-row" style="grid-template-columns: <?php echo trim($gridStyle); ?>"> <div class="dw-row__date"><?php echo htmlspecialchars($row['date']); ?></div> <?php foreach ($row['cols'] as $val): $valNum = parseTimesNum($val); $cls = ''; if ($valNum !== null) $cls = $valNum >= 1 ? 'dw-row__col--high' : 'dw-row__col--low'; ?> <div class="dw-row__col <?php echo $cls; ?>"><?php echo htmlspecialchars($val); ?></div> <?php endforeach; ?> </div> <?php endforeach; ?> </div> </div> <?php endif; ?> <!-- ===== DISCLAIMER ===== --> <div class="disclaimer-fold" id="discFold"> <button class="disclaimer-fold__head" type="button" onclick="document.getElementById('discFold').classList.toggle('open')"> <span class="disclaimer-fold__label">Disclaimer & Source</span> <svg class="disclaimer-fold__chev" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="6 9 12 15 18 9"/></svg> </button> <div class="disclaimer-fold__body"> <div class="disclaimer-fold__inner"> <p>Subscription figures are sourced from Chittorgarh and refreshed automatically during the IPO bidding window. Final numbers are confirmed only after the issue closes and the registrar publishes them.</p> <p>Data is provided as-is and may be delayed by a few minutes during peak load. For authoritative figures, please refer to the BSE / NSE bidding bulletins.</p> </div> </div> </div> <?php endif; ?> <script> // Auto-reload polling — refreshes every 60s, but only if: // (1) the tab is visible // (2) we appear to be online // (3) at least 60s have elapsed since the page became visible (so users // returning from minimize get a clean window before any reload — which // prevents net::ERR_NAME_NOT_RESOLVED on WebView resume) (function () { if (<?php echo $ipoId > 0 ? 'true' : 'false'; ?> !== true) return; var lastVisibleAt = Date.now(); document.addEventListener('visibilitychange', function () { if (!document.hidden) lastVisibleAt = Date.now(); }); setInterval(function () { if (document.hidden) return; if (navigator.onLine === false) return; if (Date.now() - lastVisibleAt < 60000) return; window.location.reload(); }, 5000); })(); </script> </body> </html>
| ver. 1.4 |
Github
|
.
| PHP 8.2.9 | Generation time: 0.01 |
proxy
|
phpinfo
|
Settings