# Çalışma saatleri: tek yapı, otomatik durum, ortak bileşen > **Kaynak:** `Core/Support/Bridges/Helpers/Library/OpeningHours.php` · `Core/Services/System/ContactService.php` · `Resources/Views/RbnCommon/Components/opening_status.rbn.php` · `Resources/Assets/RbnCommon/js/components/rbnOpeningHours.js` · `Resources/Assets/RbnCommon/css/components/rbnOpeningStatus.css` > **Veri kaynağı:** proje ayarı `contact-hours` (grup `contact`). Sayfaya giden veri `contact_info()` / `$contact` içindedir ([Iletisim-Bilgisi](Iletisim-Bilgisi.md)). Bir sitenin çalışma saati TEK yapıdır: haftalık program. Görünen metin, açık/kapalı durumu, kalan süre ve Google senkronu bu programdan türer; hiçbiri elle yazılmaz, projede saat ya da durum hesabı yapılmaz. ## 1. Veri: haftalık program (`contact-hours`) Ayar değeri JSON'dur: `mon, tue, wed, thu, fri, sat, sun` anahtarları, her biri `["AA:DD","AA:DD"]` aralıklarının listesi. ```json {"mon":[["09:00","19:00"]],"tue":[["09:00","19:00"]],"wed":[["09:00","12:00"],["13:00","19:00"]],"thu":[["09:00","19:00"]],"fri":[["18:00","02:00"]],"sat":[],"sun":[["00:00","24:00"]]} ``` | Kural | Anlamı | |---|---| | Boş liste (`[]`) | O gün kapalı | | Birden çok aralık | Öğle arası: `[["09:00","12:00"],["13:00","19:00"]]` (günde en çok 4 aralık, çakışamaz) | | `["00:00","24:00"]` | Tüm gün açık (24 saat) | | Kapanış, açılıştan sonra değilse | Gece yarısını aşar: `["18:00","02:00"]` ertesi gün 02:00'a kadar açık (aralık açıldığı günün satırında durur) | | Açılış = kapanış, `25:00`, `9:00` biçimi | Geçersiz: yazılmaz (`settings:set` ve panel reddeder) | | Hiç aralık yok | Program yok: aşağıdaki anahtarlar yoktur | | Tatil / istisna gün | **Yoktur** (kapsam dışı) | Zaman dilimi ayrı ayar değildir: framework'ün çalışma zaman dilimi (`date_default_timezone_get()`, framework varsayılanı `Europe/Istanbul`) kullanılır. Yazma yolları (hepsi aynı doğrulayıcıdan geçer, değer kanonik biçimde saklanır): panel (`hours` alan tipi, §5), `php rbn settings:set --project= --key=contact-hours --value='' [--apply]`, Google senkronu (§4). Düz metin ("Pzt - Cmt: 09:00 - 19:00") artık geçerli değer DEĞİLDİR: okunamayan değer "program yok" sayılır, yazma isteği reddedilir. ## 2. `contact_info()` / `$contact` anahtarları (saat varsa) Anahtarlar **yalnız program varsa** vardır; saatsiz sitede (marka sitesi) üçü de yoktur ve görünüm `@if(isset($contact['hours']))` ile sorar. | Anahtar | Değer | |---|---| | `hours` | Programdan üretilen görünen metin: `Pzt - Cmt: 09:00 - 19:00; Paz: Kapalı`. Ardışık aynı saatli günler birleşir, kapalı günler `Kapalı`, öğle arası `09:00 - 12:00, 13:00 - 19:00`, tüm gün `24 saat` | | `hours_schedule` | Kanonik program (yukarıdaki yapı) | | `open_status` | Şu anki durum, aşağıda | `open_status`: | Alan | Değer | |---|---| | `is_open` | `bool` | | `status_label` | Durum etiketi (açık/kapalı etiketinden): `Şu an açık`, `Şu an kapalı` | | `remaining_label` | Kalan süre metni: `Kapanmasına 45 dakika var`, `Açılmasına 5 saat 20 dakika var`, `Açılış: Pazartesi 09:00`. Hiç kapanmayan (7/24) yerde `''` | | `next_change_at` | Bir sonraki değişimin ISO-8601 anı (kapanış ya da açılış); 7/24'te `null` | | `minutes_left` | O ana kalan dakika (yukarı yuvarlanır); 7/24'te `null` | | `timezone`, `labels` | Canlı bileşenin ihtiyacı olan zaman dilimi ve çözülmüş etiket şablonları (görünüm okumaz) | Durum, sayfa üretilirken hesaplanır (`OpeningHours::status()`); önbellekli sayfada eskimesin diye bileşen tarayıcıda her dakika aynı hesabı tekrarlar (§6). ## 3. Etiketler: proje kendi cümlesini yazar Etiket şablonları proje ayarıdır (grup `contact`, isteğe bağlı, boş satır tutulmaz: girilmeyen anahtar framework varsayılanını kullanır): | Ayar anahtarı | Ne zaman | Framework varsayılanı | Yer tutucular | |---|---|---|---| | `contact-hours-open-label` | açıkken durum | `Şu an açık` | `{time}`, `{next_close}`, `{next_open}` | | `contact-hours-closed-label` | kapalıyken durum | `Şu an kapalı` | `{time}`, `{next_open}`, `{next_close}` | | `contact-hours-closing-label` | açıkken kalan süre | `Kapanmasına {time} var` | aynı | | `contact-hours-opening-label` | kapalıyken kalan süre | `Açılmasına {time} var` (bir günden uzaksa `Açılış: {next_open}`) | aynı | | Yer tutucu | Değer | |---|---| | `{time}` | Kalan süre: `45 dakika`, `5 saat 20 dakika`, `5 saat`, `1 gün 13 saat` | | `{next_open}` | Bir sonraki açılış: `Bugün 09:00`, `Yarın 09:00`, `Pazartesi 09:00` | | `{next_close}` | Bir sonraki kapanış: `19:00` (bugünse yalnız saat), `Yarın 02:00` | Örnekler: kapalı etiketi `Kapalı` ya da `Şu an kapalı`; açılış etiketi `Açılmasına {time} var` ya da `{time} sonra açığız` ya da `Açılış: {next_open}`; açık etiketi `Açığız`; kapanış etiketi `{next_close} kapanıyoruz`. **Uzak açılış kararı:** framework varsayılanı, açılışa bir gün (1440 dakika) ya da daha fazla varsa `Açılmasına {time} var` yerine `Açılış: {next_open}` yazar (`Açılmasına 1 gün 13 saat var` yerine `Açılış: Pazartesi 09:00`): gün adı ve saat ziyaretçiye süreden daha kullanışlıdır, Türkçe ek (`09:00'da`) gerektirmez. Proje `contact-hours-opening-label` yazdıysa onun cümlesi her sürede korunur. Varsayılan etiketler, gün adları ve süre kelimeleri `OpeningHours::DEFAULT_LABELS` / `OpeningHours::VOCABULARY` içindedir (framework dil kaynağı); tarayıcıya aynı liste gönderilir, JS'te ayrı bir dil yoktur. ## 4. Google senkronu aynı yapıya yazar `rbn google:sync` / haftalık `google_sync` görevi, Google `regularOpeningHours.periods` listesini `OpeningHours::fromGooglePeriods()` ile aynı programa çevirip `contact-hours`'a yazar (gün numarası 0 = Pazar; gece yarısını aşan periyot, kapanışsız 7/24 periyot ve aynı günde birden çok periyot desteklenir). Temsil edilemeyen periyot (iki günden uzun) için hiçbir değer üretilmez (tahmin yok): ayar olduğu gibi kalır. `weekdayDescriptions` metni okunmaz. Katılım koşulları ve diğer alanlar: [Iletisim-Bilgisi §3](Iletisim-Bilgisi.md). ## 5. Panel: `hours` alan tipi `contact-hours` ayarının alan tipi `hours`'dır (`RenderFieldHelper` `renderHours()`): gün başına "açık" anahtarı, "24 saat" anahtarı ve iki saat aralığı (ikincisi öğle arası). `rbnOpeningHours.js` her değişiklikte gizli alana kanonik JSON'u yazar; `SettingsService::updateSettings()` kaydederken programı doğrular ve kanonik biçimde saklar (geçersizse hiçbir şey kaydedilmez). Etiket ayarları düz metin alanlarıdır. ## 6. Bileşen: `opening_status` Ortak görünüm parçası; proje kendi tasarımının içine yerleştirir: ```php @if(isset($contact['hours']))
Çalışma Saatleri: {{ $contact['hours'] }} @import('framework', 'Resources/Views/RbnCommon/Components/opening_status.rbn.php')
@endif ``` Parça `$contact`'ı okur; saat yoksa hiçbir şey basmaz. Çıktı: `role="status"` + nokta (`rbn-opening-status__dot`) + durum metni + kalan süre. **Açık yeşil, kapalı kırmızı** (`--rbn-success` / `--rbn-danger`, metinde AA kontrastlı `--rbn-success-text` / `--rbn-danger-text`); renk tek başına bilgi taşımaz (nokta + metin). Sabit renk yoktur: proje yalnız token değerini (`--success-color`, `--danger-color`, `--success-text`, `--danger-text`) kendi CSS'inde değiştirir, sınıfları yeniden yazmaz. Yerleşim ve çerçeve projededir. `aria-live="off"`: dakikalık güncelleme ekran okuyucuyu sürekli konuşturmaz. **Canlı güncelleme:** `rbn-master.js` `components/rbnOpeningHours.js`'i yükler. Sunucu ilk durumu basar; öğede `data-config` (program, zaman dilimi, etiket şablonları, kelime listesi) bulunur ve bileşen dakika başında durumu, kalan süreyi ve `--open` / `--closed` sınıfını günceller (HTML/sayfa önbelleği eski durumu gösteremez). JS çalışmazsa sunucu çıktısı geçerlidir. Sunucu (PHP) ve istemci (JS) aynı algoritmayı çalıştırır: duvar saati hafta-dakikasında (`gün * 1440 + gün içi dakika`) aralıkların birleştirilmesi; kapı `G-saat-10` ikisini aynı vakalarla karşılaştırır. ## 7. Kodda kullanım ```php use Rbn\Framework\Core\Support\Bridges\Helpers\Library\OpeningHours; $program = OpeningHours::parse($json); // doğrular, kanonik program ([] = yok); geçersizse InvalidArgumentException OpeningHours::text($program); // 'Pzt - Cmt: 09:00 - 19:00; Paz: Kapalı' OpeningHours::status($program, new DateTimeImmutable('now'), 'Europe/Istanbul', OpeningHours::labels($contactAyarlari)); OpeningHours::fromGooglePeriods($places['regularOpeningHours']['periods']); ``` Projede saat hesabı, "şu an açık" kararı, sabit saat metni ya da elle yazılmış açık/kapalı rozeti bulunmaz; görünüm `$contact['open_status']` ve framework parçasını kullanır. ## 8. Kapılar `E:\AgentSpace\.agentspace\araclar\fw-regresyon\birim\g_calisma_saati.php`: `G-saat-01` durum ve kalan süre · `-02` gece yarısını aşan aralık · `-03` öğle arası · `-04` 24 saat, 7/24, kapalı gün · `-05` zaman dilimi · `-06` etiket yer tutucuları ve varsayılanlar · `-07` görünen metin gruplaması · `-08` Google periods dönüşümü · `-09` program doğrulama · `-10` sunucu = istemci (3.420 vaka) · `-11` projede saat/durum hesabı yok · `-12` bileşende sabit renk yok · `-13` Google senkronu aynı yapıya yazar · `-14` pilot (saatli sitede anahtarlar + bileşen, saatsiz sitede anahtar yok) · `-15` ayar şablonu · `-16` panel izgarası · `-17` yazma yolu doğrulaması. Her biri `-neg` örnekle ya da bozuk ağaç kopyasıyla kırmızıya döner.