{{-- ============================================================================ 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); $tndTabUrl = fn (string $key) => url()->current().'?tab='.$key; $tndUrl = function (array $params = []) use ($tndBase, $tndTab, $tndType, $tndId) { $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), ], 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; $tndTypeLabel = ['TENDER' => 'Tender', 'SEBUT_HARGA' => 'Sebut Harga']; // Tarikh & masa 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; } }; $tndTime = function ($value) { if (blank($value)) { return ''; } try { return \Carbon\Carbon::parse($value)->format('h:i A'); } 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'); $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
{{-- ---------- BREADCRUMB ---------- --}} {{-- ---------- TAJUK ---------- --}}
Perkhidmatan

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

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

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

{{ $tndDetail['title'] }}

No. Rujukan: {{ $tndDetail['code'] }}

@if ($tndDetail['open_date'])
{{ t('tq.col_open') }} {{ $tndDate($tndDetail['open_date']) }} @if ($tndDetail['open_time'] !== '') {{ $tndTime($tndDetail['open_time']) }} @endif
@endif @if ($tndDetail['close_date'])
{{ t('tq.col_close') }} {{ $tndDate($tndDetail['close_date']) }} @if ($tndDetail['close_time'] !== '') {{ $tndTime($tndDetail['close_time']) }} @endif
@endif @if ($tndDetail['brief_date'])
Taklimat {{ $tndDate($tndDetail['brief_date']) }} @if ($tndDetail['brief_time'] !== '') {{ $tndTime($tndDetail['brief_time']) }} @endif @if ($tndDetail['brief_place'] !== '') {{ $tndDetail['brief_place'] }} @endif
@endif @if ($tndDetail['visit_date'])
Lawatan Tapak {{ $tndDate($tndDetail['visit_date']) }}
@endif
@if ($tndDetail['descr'] !== '')

Deskripsi

{{ $tndDetail['descr'] }}

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

Skop Kerja

{{ $tndDetail['scope'] }}

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

Kelayakan

{{ $tndDetail['eligibility'] }}

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

Dokumen Tender

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

Keputusan

@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'] !== '')

Hubungan & Pautan

@if ($tndDetail['contact']['name'] !== '' || $tndDetail['contact']['phone'] !== '' || $tndDetail['contact']['email'] !== '')
@if ($tndDetail['contact']['name'] !== '')
Pegawai
{{ $tndDetail['contact']['name'] }}
@endif @if ($tndDetail['contact']['phone'] !== '')
Telefon
{{ $tndDetail['contact']['phone'] }}
@endif @if ($tndDetail['contact']['email'] !== '')
E-mel
{{ $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 }} sedang dibuka @endif @if ($tndType !== '') jenis: {{ $tndTypeLabel[$tndType] }} @endif

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

@forelse ($tndOffers as $tndOffer) @empty @endforelse
# {{ t('tq.title_reference_no') }} {{ t('tq.col_category') }} {{ t('tq.col_method') }} {{ t('tq.col_open') }} {{ t('tq.col_close') }} {{ t('tq.col_status') }} {{ t('tq.col_document') }}
{{ $loop->iteration }}

{{ $tndOffer['title'] }}

{{ $tndOffer['code'] }}
{{ $tndTypeLabel[$tndOffer['type']] ?? $tndOffer['type'] }}
{{ $tndLabel($tndOffer['category']) }} {{ $tndOffer['method'] !== '' ? $tndLabel($tndOffer['method']) : '—' }} {{ $tndOffer['open_date'] ? $tndDate($tndOffer['open_date']) : '—' }} @if ($tndOffer['open_time'] !== '') {{ $tndTime($tndOffer['open_time']) }} @endif {{ $tndOffer['close_date'] ? $tndDate($tndOffer['close_date']) : '—' }} @if ($tndOffer['close_time'] !== '') {{ $tndTime($tndOffer['close_time']) }} @endif {{ $tndOffer['is_open'] ? t('tq.status_open') : t('tq.status_closed') }}
@if ($tndOffer['document'] !== '') {{ t('tq.download') }} @endif @if (count($tndOffer['docs'])) {{ t('tq.attachment') }}{{ count($tndOffer['docs']) }}) @endif @if ($tndOffer['document'] === '' && ! count($tndOffer['docs'])) — @endif
@if ($tndType !== '') Tiada tawaran {{ $tndTypeLabel[$tndType] }} pada masa ini. Tampilkan semua. @else Tiada tawaran tender atau sebut harga pada masa ini. @endif
@else {{-- ---------- TAB: KEPUTUSAN TENDER / SEBUT HARGA ---------- --}} @php $tndIsTenderTab = $tndTab === 'keputusan-tender'; $tndResultRows = $tndIsTenderTab ? $tndResultTender : $tndResultQuotation; $tndResultKind = $tndIsTenderTab ? 'Tender' : 'Sebut Harga'; @endphp

{{ count($tndResultRows) }} keputusan {{ mb_strtolower($tndResultKind) }} telah dimuktamadkan

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

@forelse ($tndResultRows as $tndResult) @empty @endforelse
# {{ t('tq.title_reference_no') }} {{ t('tq.col_category') }} {{ t('tq.col_close') }} Keputusan
{{ $loop->iteration }}

{{ $tndResult['title'] }}

{{ $tndResult['code'] }}
{{ $tndTypeLabel[$tndResult['type']] ?? $tndResult['type'] }}
{{ $tndLabel($tndResult['category']) }} {{ $tndResult['close_date'] ? $tndDate($tndResult['close_date']) : '—' }}
@if ($tndResult['result_doc'] !== '') Dokumen Keputusan @endif @if ($tndResult['result_note'] !== '') {{ \Illuminate\Support\Str::limit($tndResult['result_note'], 140) }} @endif
Belum ada keputusan {{ mb_strtolower($tndResultKind) }} diterbitkan.
@endif @endif {{-- ---------- NOTA ---------- --}}