{{-- ============================================================================ PAGE CONTENT — Tender dan Sebutharga Site : nres · Page slug: tenders-and-quotations · Page ID: 31 Sumber: modul content-tender · content_tender → kod, jenis, kategori, kaedah, status, tarikh · content_tender_translation → tajuk, deskripsi, kelayakan, skop kerja · content_tender_document → dokumen lampiran (label + fail) Konsep: https://www.nres.gov.my/TenderSebutharga/Pages/default.aspx (tab: Tawaran Tender & Sebutharga · Keputusan Tender · Keputusan Sebutharga) Parameter URL: tab tawaran (lalai) | keputusan-tender | keputusan-sebutharga jenis TENDER | SEBUT_HARGA (tab tawaran sahaja) id id tender → papar butiran penuh Nota: · SEMUA logik + markup + CSS ada dalam fail ini — tiada komponen, tiada partial. · Hanya tender_status = PUBLISHED dipaparkan (DRAFT/CANCELLED tersembunyi). · Fail disimpan pada disk 'public' (content-tender/files|results|attachments) → URL = asset('storage/'.$path). · "Keputusan" = tender yang ada tender_result_document atau tender_result_notes. · Warna guna CSS variable tema (--teal/--green/--fade/--line/--ink) → sokong dark mode. ============================================================================ --}} @php /* -------------------------------------------------------------------- | 1. Parameter & konteks -------------------------------------------------------------------- */ $tndBase = url()->current(); $tndQuery = request()->query(); $tndLang = ($lang ?? session('locale', 'ms')) === 'en' ? 'en' : 'ms'; $tndTab = (string) ($tndQuery['tab'] ?? 'tawaran'); if (! in_array($tndTab, ['tawaran', 'keputusan-tender', 'keputusan-sebutharga'], true)) { $tndTab = 'tawaran'; } $tndType = strtoupper((string) ($tndQuery['jenis'] ?? '')); $tndType = in_array($tndType, ['TENDER', 'SEBUT_HARGA'], true) ? $tndType : ''; $tndId = (int) ($tndQuery['id'] ?? 0); // Penomboran: 10 baris setiap halaman (?page=) $tndPerPage = 10; $tndPage = max(1, (int) ($tndQuery['page'] ?? 1)); $tndTabUrl = fn (string $key) => url()->current().'?tab='.$key; $tndUrl = function (array $params = []) use ($tndBase, $tndTab, $tndType, $tndId, $tndPage) { $query = array_filter([ 'tab' => array_key_exists('tab', $params) ? $params['tab'] : $tndTab, 'jenis' => array_key_exists('jenis', $params) ? $params['jenis'] : $tndType, 'id' => array_key_exists('id', $params) ? $params['id'] : ($tndId ?: null), 'page' => array_key_exists('page', $params) ? $params['page'] : ($tndPage > 1 ? $tndPage : null), ], fn ($v) => $v !== null && $v !== ''); return $query ? $tndBase.'?'.http_build_query($query) : $tndBase; }; // Fail pada disk 'public' → URL awam $tndFile = function ($path) { $path = trim((string) $path); if ($path === '') { return ''; } if (str_starts_with($path, 'http://') || str_starts_with($path, 'https://')) { return $path; } return asset('storage/'.ltrim($path, '/')); }; /* -------------------------------------------------------------------- | 2. Rujukan (jenis / kategori / kaedah / status) -------------------------------------------------------------------- */ $tndRefLabel = []; foreach (['TENDER_TYPE', 'TENDER_CATEGORY', 'TENDER_METHOD', 'TENDER_STATUS'] as $tndCat) { foreach (DB::table('ref')->where('cat', $tndCat)->get() as $tndRef) { $tndRefLabel[(string) $tndRef->code] = $tndLang === 'en' ? ((string) ($tndRef->descr_en ?: $tndRef->descr)) : ((string) ($tndRef->descr ?: $tndRef->descr_en)); } } $tndLabel = fn ($code) => $tndRefLabel[(string) $code] ?? (string) $code; // Ikut bahasa semasa (ref.descr / ref.descr_en) — jangan keras Melayu. $tndTypeLabel = [ 'TENDER' => $tndRefLabel['TENDER'] ?? 'Tender', 'SEBUT_HARGA' => $tndRefLabel['SEBUT_HARGA'] ?? 'Sebut Harga', ]; // Tarikh paparan $tndMonths = $tndLang === 'en' ? [1 => 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'] : [1 => 'Januari', 'Februari', 'Mac', 'April', 'Mei', 'Jun', 'Julai', 'Ogos', 'September', 'Oktober', 'November', 'Disember']; $tndDate = function ($value) use ($tndMonths) { if (blank($value)) { return ''; } try { $date = \Carbon\Carbon::parse($value); return $date->day.' '.$tndMonths[(int) $date->month].' '.$date->year; } catch (\Throwable $e) { return (string) $value; } }; /* -------------------------------------------------------------------- | 3. Tender PUBLISHED + terjemahan + dokumen lampiran -------------------------------------------------------------------- */ $tndRows = DB::table('content_tender') ->where('tender_status', 'PUBLISHED') ->orderBy('tender_sorting') ->orderByDesc('tender_close_date') ->orderByDesc('tender_id') ->get(); $tndIds = $tndRows->pluck('tender_id')->all(); $tndTr = $tndIds ? DB::table('content_tender_translation')->whereIn('tender_id', $tndIds)->get()->groupBy('tender_id') : collect(); $tndDocs = $tndIds ? DB::table('content_tender_document')->whereIn('tender_id', $tndIds)->orderBy('sort')->orderBy('id')->get()->groupBy('tender_id') : collect(); $tndItems = []; foreach ($tndRows as $tndRow) { $tndTrRows = $tndTr[$tndRow->tender_id] ?? collect(); $tndTrRow = $tndTrRows->firstWhere('language', $tndLang) ?? $tndTrRows->firstWhere('main', 1) ?? $tndTrRows->first(); $tndCloseAt = $tndRow->tender_close_date ? \Carbon\Carbon::parse($tndRow->tender_close_date.' '.($tndRow->tender_close_time ?: '23:59:59')) : null; $tndOpenAt = $tndRow->tender_open_date ? \Carbon\Carbon::parse($tndRow->tender_open_date.' '.($tndRow->tender_open_time ?: '00:00:00')) : null; $tndIsOpen = ($tndOpenAt === null || now()->gte($tndOpenAt)) && ($tndCloseAt === null || now()->lte($tndCloseAt)); $tndItems[] = [ 'id' => (int) $tndRow->tender_id, 'code' => (string) $tndRow->tender_code, 'type' => (string) $tndRow->tender_type, 'category' => (string) $tndRow->tender_category, 'method' => (string) ($tndRow->tender_method ?? ''), 'title' => (string) ($tndTrRow->title ?? $tndRow->tender_code), 'descr' => (string) ($tndTrRow->description ?? ''), 'eligibility' => (string) ($tndTrRow->eligibility ?? ''), 'scope' => (string) ($tndTrRow->scope_of_work ?? ''), 'open_date' => $tndRow->tender_open_date, 'open_time' => (string) ($tndRow->tender_open_time ?? ''), 'close_date' => $tndRow->tender_close_date, 'close_time' => (string) ($tndRow->tender_close_time ?? ''), 'brief_date' => $tndRow->tender_briefing_date, 'brief_time' => (string) ($tndRow->tender_briefing_time ?? ''), 'brief_place' => (string) ($tndRow->tender_briefing_place ?? ''), 'visit_date' => $tndRow->tender_site_visit_date, 'document' => $tndFile($tndRow->tender_document), 'result_doc' => $tndFile($tndRow->tender_result_document), 'result_note' => (string) ($tndRow->tender_result_notes ?? ''), 'ref_url' => (string) ($tndRow->tender_reference_url ?? ''), 'contact' => [ 'name' => (string) ($tndRow->tender_contact_name ?? ''), 'phone' => (string) ($tndRow->tender_contact_phone ?? ''), 'email' => (string) ($tndRow->tender_contact_email ?? ''), ], 'is_open' => $tndIsOpen, 'has_result' => filled($tndRow->tender_result_document) || filled($tndRow->tender_result_notes), 'docs' => ($tndDocs[$tndRow->tender_id] ?? collect())->map(fn ($tndDoc) => [ 'label' => (string) ($tndDoc->label ?: basename((string) $tndDoc->file)), 'url' => $tndFile($tndDoc->file), ])->all(), ]; } /* -------------------------------------------------------------------- | 4. Kumpulan mengikut tab -------------------------------------------------------------------- */ $tndOffers = array_values(array_filter( $tndItems, fn ($tndItem) => $tndType === '' || $tndItem['type'] === $tndType )); // Tawaran: yang masih dibuka dahulu (tarikh tutup menaik), kemudian yang ditutup (terbaru dahulu) usort($tndOffers, function ($a, $b) { if ($a['is_open'] !== $b['is_open']) { return $a['is_open'] ? -1 : 1; } $aClose = (string) $a['close_date']; $bClose = (string) $b['close_date']; return $a['is_open'] ? strcmp($aClose, $bClose) : strcmp($bClose, $aClose); }); $tndByType = function (string $type) use ($tndItems) { $rows = array_values(array_filter($tndItems, fn ($tndItem) => $tndItem['type'] === $type && $tndItem['has_result'])); usort($rows, fn ($a, $b) => strcmp((string) $b['close_date'], (string) $a['close_date'])); return $rows; }; $tndResultTender = $tndByType('TENDER'); $tndResultQuotation = $tndByType('SEBUT_HARGA'); /* -------------------------------------------------------------------- | 4b. Penomboran — 10 baris setiap halaman -------------------------------------------------------------------- */ $tndPaged = function (array $rows) use ($tndPage, $tndPerPage) { $total = count($rows); $last = max(1, (int) ceil($total / $tndPerPage)); $page = min(max(1, $tndPage), $last); return [ 'rows' => array_slice($rows, ($page - 1) * $tndPerPage, $tndPerPage), 'page' => $page, 'last' => $last, 'total' => $total, ]; }; $tndOffersPage = $tndPaged($tndOffers); $tndResultPage = $tndPaged($tndTab === 'keputusan-tender' ? $tndResultTender : $tndResultQuotation); $tndTotal = count($tndItems); $tndOpenCnt = count(array_filter($tndItems, fn ($tndItem) => $tndItem['is_open'])); /* -------------------------------------------------------------------- | 5. Butiran penuh (id) -------------------------------------------------------------------- */ $tndDetail = null; if ($tndId) { foreach ($tndItems as $tndItem) { if ($tndItem['id'] === $tndId) { $tndDetail = $tndItem; break; } } } @endphp
{{-- ---------- BANNER (breadcrumb + tajuk) ---------- --}}
{{ t('tq.eyebrow_service') }}

{{ $tndDetail ? $tndDetail['title'] : t('tq.title') }}

@if ($tndDetail)

{{ t('tq.detail_lead') }}

@else

{{ t('tq.hero_desc') }}

@endif
{{-- ---------- TAB ---------- --}} @if ($tndDetail) {{-- ---------- BUTIRAN TENDER ---------- --}} {{ t('tq.back_to_list') }}
{{ $tndTypeLabel[$tndDetail['type']] ?? $tndDetail['type'] }} @if ($tndDetail['category'] !== '') {{ $tndLabel($tndDetail['category']) }} @endif @if ($tndDetail['method'] !== '') {{ $tndLabel($tndDetail['method']) }} @endif {{ $tndDetail['is_open'] ? t('tq.status_open') : t('tq.status_closed') }}

{{ $tndDetail['title'] }}

{{ t('tq.ref_no') }} {{ $tndDetail['code'] }}

@if ($tndDetail['open_date'])
{{ t('tq.col_open') }} {{ $tndDate($tndDetail['open_date']) }}
@endif @if ($tndDetail['close_date'])
{{ t('tq.col_close') }} {{ $tndDate($tndDetail['close_date']) }}
@endif @if ($tndDetail['brief_date'])
{{ t('tq.briefing') }} {{ $tndDate($tndDetail['brief_date']) }} @if ($tndDetail['brief_place'] !== '') {{ $tndDetail['brief_place'] }} @endif
@endif @if ($tndDetail['visit_date'])
{{ t('tq.site_visit') }} {{ $tndDate($tndDetail['visit_date']) }}
@endif
@if ($tndDetail['descr'] !== '')

{{ t('tq.description') }}

{{ $tndDetail['descr'] }}

@endif @if ($tndDetail['scope'] !== '')

{{ t('tq.scope') }}

{{ $tndDetail['scope'] }}

@endif @if ($tndDetail['eligibility'] !== '')

{{ t('tq.eligibility') }}

{{ $tndDetail['eligibility'] }}

@endif @if ($tndDetail['document'] !== '' || count($tndDetail['docs']))

{{ t('tq.documents') }}

@if ($tndDetail['document'] !== '') {{ t('tq.doc_main') }} @endif @foreach ($tndDetail['docs'] as $tndDocItem) {{ $tndDocItem['label'] }} @endforeach
@endif @if ($tndDetail['result_doc'] !== '' || $tndDetail['result_note'] !== '')

{{ t('tq.result') }}

@if ($tndDetail['result_note'] !== '')

{{ $tndDetail['result_note'] }}

@endif @if ($tndDetail['result_doc'] !== '') @endif
@endif @if ($tndDetail['contact']['name'] !== '' || $tndDetail['contact']['phone'] !== '' || $tndDetail['contact']['email'] !== '' || $tndDetail['ref_url'] !== '')

{{ t('tq.contact_links') }}

@if ($tndDetail['contact']['name'] !== '' || $tndDetail['contact']['phone'] !== '' || $tndDetail['contact']['email'] !== '')
@if ($tndDetail['contact']['name'] !== '')
{{ t('tq.officer') }}
{{ $tndDetail['contact']['name'] }}
@endif @if ($tndDetail['contact']['phone'] !== '')
{{ t('tq.phone') }}
{{ $tndDetail['contact']['phone'] }}
@endif @if ($tndDetail['contact']['email'] !== '')
{{ t('tq.email') }}
{{ $tndDetail['contact']['email'] }}
@endif
@endif @if ($tndDetail['ref_url'] !== '') @endif
@endif
@else @if ($tndTab === 'tawaran') {{-- ---------- TAB: TAWARAN TENDER & SEBUTHARGA ---------- --}}

{{ count($tndOffers) }} {{ t('tq.offers_shown') }} @if ($tndOpenCnt > 0) {{ $tndOpenCnt }} {{ t('tq.open_now') }} @endif @if ($tndType !== '') {{ t('tq.filter_type') }} {{ $tndTypeLabel[$tndType] }} @endif

{{ t('tq.table_hint') }}

@forelse ($tndOffersPage['rows'] as $tndOffer) @empty @endforelse
{{ $tndType === 'SEBUT_HARGA' ? t('tq.col_quotation_no') : ($tndType === 'TENDER' ? t('tq.col_tender_no') : t('tq.col_tender_quotation_no')) }} {{ t('tq.col_title') }} {{ t('tq.col_start_date') }} {{ t('tq.col_due_date') }} {{ t('tq.col_eprocurement') }}
{{ $tndOffer['code'] }} @if ($tndType === '')
{{ $tndTypeLabel[$tndOffer['type']] ?? $tndOffer['type'] }}
@endif

{{ $tndOffer['title'] }}

{{ $tndOffer['open_date'] ? $tndDate($tndOffer['open_date']) : '—' }} {{ $tndOffer['close_date'] ? $tndDate($tndOffer['close_date']) : '—' }} @if ($tndOffer['ref_url'] !== '') {{ t('tq.eprocurement') }} @else — @endif
@if ($tndType !== '') {{ str_replace(':type', $tndTypeLabel[$tndType], t('tq.empty_offers_type')) }} {{ t('tq.show_all') }}. @else {{ t('tq.empty_offers') }} @endif
@if ($tndOffersPage['total'] > 0) @endif @else {{-- ---------- TAB: KEPUTUSAN TENDER / SEBUT HARGA ---------- --}} @php $tndIsTenderTab = $tndTab === 'keputusan-tender'; $tndResultRows = $tndIsTenderTab ? $tndResultTender : $tndResultQuotation; $tndResultType = mb_strtolower($tndTypeLabel[$tndIsTenderTab ? 'TENDER' : 'SEBUT_HARGA']); @endphp

{{ count($tndResultRows) }} {{ str_replace(':type', $tndResultType, t('tq.results_concluded')) }}

{{ t('tq.table_hint') }}

@forelse ($tndResultPage['rows'] as $tndResult) @empty @endforelse
{{ t('tq.col_year') }} {{ $tndIsTenderTab ? t('tq.col_tender_no') : t('tq.col_quotation_no') }} {{ $tndIsTenderTab ? t('tq.col_tender_title') : t('tq.col_quotation_title') }} {{ t('tq.col_info_link') }}
{{ $tndResult['close_date'] ? substr((string) $tndResult['close_date'], 0, 4) : '—' }} {{ $tndResult['code'] }}

{{ $tndResult['title'] }}

@if ($tndResult['result_doc'] !== '') {{ t('tq.download') }} @else — @endif
{{ str_replace(':type', $tndResultType, t('tq.empty_results')) }}
@if ($tndResultPage['total'] > 0) @endif @endif @endif