From 1ca20b6f53ece9ad22cbc23dd518b4dd0d3088bd Mon Sep 17 00:00:00 2001 From: hamed <15238-genius.ha@users.noreply.drupalcode.org> Date: Wed, 19 Aug 2026 14:54:06 +0330 Subject: [PATCH] feat(public): add About Us page MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds a public "درباره ما" page at /درباره-ما reusing the landing theme (same webpack entry, header, footer, registration modal). Section ids match the header anchors so the nav works on this page too. The explicit route takes precedence over LandingController's catch-all /{slug}, which is registered with priority -10. Also links it from the header nav and footer quick links, and lists it in sitemap.xml. Co-Authored-By: Claude Opus 5 (1M context) --- src/Shared/Controller/AboutController.php | 29 +++ src/Shared/Controller/SeoController.php | 3 +- templates/public/_footer.html.twig | 1 + templates/public/_header.html.twig | 1 + templates/public/about.html.twig | 216 ++++++++++++++++++++++ tests/Shared/AboutPageTest.php | 48 +++++ tests/Shared/LandingPageTest.php | 6 +- 7 files changed, 300 insertions(+), 4 deletions(-) create mode 100644 src/Shared/Controller/AboutController.php create mode 100644 templates/public/about.html.twig create mode 100644 tests/Shared/AboutPageTest.php diff --git a/src/Shared/Controller/AboutController.php b/src/Shared/Controller/AboutController.php new file mode 100644 index 00000000..140f1d21 --- /dev/null +++ b/src/Shared/Controller/AboutController.php @@ -0,0 +1,29 @@ +render('public/about.html.twig', [ + 'altcha_enabled' => $this->altcha->enabled(), + ]); + } +} diff --git a/src/Shared/Controller/SeoController.php b/src/Shared/Controller/SeoController.php index 08b9f6f5..c31499f5 100644 --- a/src/Shared/Controller/SeoController.php +++ b/src/Shared/Controller/SeoController.php @@ -36,7 +36,8 @@ class SeoController extends AbstractController $xml = '' . "\n" . '' . "\n" - . $this->urlNode("{$base}/", 'weekly', '1.0'); + . $this->urlNode("{$base}/", 'weekly', '1.0') + . $this->urlNode($base . '/' . rawurlencode(AboutController::SLUG), 'yearly', '0.5'); // اسلاگ‌ها فارسی‌اند و باید percent-encode شوند، وگرنه XML نامعتبر است. foreach ($this->landings->all() as $page) { diff --git a/templates/public/_footer.html.twig b/templates/public/_footer.html.twig index c81e2833..d91017d3 100644 --- a/templates/public/_footer.html.twig +++ b/templates/public/_footer.html.twig @@ -29,6 +29,7 @@ امکانات چرا کلینیک پرو دانلود نرم‌افزار + دربارهٔ ما تماس با ما diff --git a/templates/public/_header.html.twig b/templates/public/_header.html.twig index 7c342c31..56267bb6 100644 --- a/templates/public/_header.html.twig +++ b/templates/public/_header.html.twig @@ -12,6 +12,7 @@ امکانات چرا کلینیک پرو دانلود + دربارهٔ ما تماس با ما ثبت نام diff --git a/templates/public/about.html.twig b/templates/public/about.html.twig new file mode 100644 index 00000000..0123492a --- /dev/null +++ b/templates/public/about.html.twig @@ -0,0 +1,216 @@ +{# صفحهٔ «دربارهٔ ما». همان تم صفحهٔ اصلی: همان entry وبپک، همان هدر و فوتر و مودال. + idهای بخش‌ها (hero/features/why/contact) عمداً با لینک‌های هدر یکی است تا منو + در این صفحه هم کار کند. #} +{% set base = app.request.schemeAndHttpHost %} +{% set url = base ~ '/درباره-ما' %} + + + + + + دربارهٔ ما | کلینیک پرو + + + + + + + + + + + + + + + + + + + + + {# JSON-LD با json_encode ساخته می‌شود نه رشتهٔ دستی: متن فارسی نقل‌قول و + کاراکتر کنترلی دارد و JSONِ دست‌ساز در Twig خیلی راحت نامعتبر می‌شود. #} + + + {{ encore_entry_link_tags('home') }} + + + + {{ include('public/_header.html.twig') }} + +
+
+
+
+

دربارهٔ کلینیک پرو

+

ما تیمی هستیم که سال‌ها کنار پزشک‌ها و منشی‌ها نشسته و کار روزمرهٔ مطب را از نزدیک دیده‌ایم. کلینیک پرو حاصل همان دیدن است: نرم‌افزاری که به‌جای اضافه‌کردن کار، کار را کم می‌کند.

+
+ {# همان idهایی که اسکریپت مودال به آن‌ها bind می‌شود. #} + + تماس با ما +
+
+ {{ include('public/_hero_art.html.twig') }} +
+
+ +
+
+
+ داستان ما +

از یک دفتر کاغذی شروع شد

+

ایدهٔ کلینیک پرو از یک مشکل ساده بیرون آمد: نوبت‌ها روی کاغذ، حساب‌ها در ذهن و پروندهٔ بیمار در کشو.

+
+
+
+

مشاهده

+

چند فصل در مطب‌ها نشستیم و دیدیم بیشترِ وقت منشی صرف پیدا کردن یک پرونده و هماهنگی دوبارهٔ نوبت می‌شود.

+
+
+

ساخت

+

اولین نسخه را برای یک مطب نوشتیم و هر هفته کنار خودشان اصلاحش کردیم؛ نه از روی حدس، از روی کار واقعی.

+
+
+

گسترش

+

امروز کلینیک پرو از مطب تک‌پزشکه تا درمانگاه چندتخصصی را پوشش می‌دهد؛ با نوبت‌دهی آنلاین، پرونده، بیمه و حسابداری.

+
+
+

ادامه

+

هر قابلیت تازه از درخواست کاربرها می‌آید. مسیر محصول را کسانی می‌سازند که هر روز با آن کار می‌کنند.

+
+
+
+
+ +
+
+
+

کارِ مطب، سرِ جای خودش

+

نوبت، پرونده، نسخه، بیمه و صندوق در یک جا جمع می‌شود؛ دیگر لازم نیست بین چند دفتر و چند فایل بگردید.

+
+
+

ساده بماند

+

هر صفحه را تا جایی ساده می‌کنیم که منشی تازه‌وارد بدون آموزش طولانی بتواند کار کند.

+
+
+

اطلاعات مالِ شماست

+

داده‌های بیماران شما فقط برای شماست. پشتیبان‌گیری منظم و دسترسی نقش‌محور از روز اول در محصول بوده است.

+
+
+

کنار شما می‌مانیم

+

راه‌اندازی، انتقال اطلاعات و آموزش تیم را خودمان انجام می‌دهیم؛ فروش پایان کار نیست، شروع آن است.

+
+
+
+ +
+
+
+
+
+ +
+

ساخت ایران، برای ایران

+

تقویم شمسی، بیمه‌های داخلی، پیامک فارسی و روال واقعی مطب‌های ایرانی؛ نه ترجمهٔ یک محصول خارجی.

+
+
+
+ +
+

امانت‌داری در داده

+

پروندهٔ بیمار امانت است. دسترسی‌ها دقیق تعریف می‌شود و هر تغییر مهم ثبت و قابل پیگیری است.

+
+
+
+ +
+

حرف کاربر، خطِ اول

+

هر بازخورد خوانده می‌شود. بخش بزرگی از قابلیت‌های امروز، درخواست پزشک‌ها و منشی‌ها بوده است.

+
+
+
+ +
+

رشد پیوسته

+

محصول هر ماه به‌روز می‌شود و به‌روزرسانی‌ها برای مشترکان فعال رایگان است.

+
+
+
+
+ +
+
+
+ پشت محصول +

شرکت توسعه فناوری اطلاعات حامی

+

کلینیک پرو محصول این شرکت است؛ تیمی از توسعه‌دهنده، طراح و کارشناس پشتیبانی که همگی روی یک محصول کار می‌کنند.

+
+
+
+

تیم محصول

+

طراحی و توسعهٔ وب، دسکتاپ و موبایل؛ همه با یک هستهٔ مشترک تا رفتار محصول همه‌جا یکسان بماند.

+
+
+

پشتیبانی

+

تماس، پیام و راه دور؛ مشکل شما تا حل‌شدن پیگیری می‌شود، نه تا بسته‌شدن تیکت.

+
+
+

راه‌اندازی

+

انتقال اطلاعات از دفتر یا نرم‌افزار قبلی و آموزش تیم مطب را کنار خودتان انجام می‌دهیم.

+
+
+

همکاری

+

برای نمایندگی، همکاری فنی یا پیشنهاد قابلیت تازه، از همین صفحه با ما تماس بگیرید.

+
+
+
+
+ + {{ include('public/_reg_modal.html.twig') }} +
+ + {{ include('public/_footer.html.twig') }} + {{ include('public/_page_scripts.html.twig') }} + {{ encore_entry_script_tags('home') }} + + diff --git a/tests/Shared/AboutPageTest.php b/tests/Shared/AboutPageTest.php new file mode 100644 index 00000000..700914ac --- /dev/null +++ b/tests/Shared/AboutPageTest.php @@ -0,0 +1,48 @@ +client = static::createClient(); + } + + public function testAboutPageRenders(): void + { + $this->client->request('GET', '/' . AboutController::SLUG); + $html = $this->client->getResponse()->getContent(); + + self::assertSame(200, $this->client->getResponse()->getStatusCode()); + self::assertStringContainsString('

دربارهٔ کلینیک پرو

', $html); + self::assertStringContainsString('دربارهٔ ما | کلینیک پرو', $html); + self::assertStringContainsString('شرکت توسعه فناوری اطلاعات حامی', $html); + } + + public function testHeaderLinksToAbout(): void + { + $this->client->request('GET', '/'); + + self::assertStringContainsString('href="/درباره-ما"', $this->client->getResponse()->getContent()); + } + + public function testSitemapListsAbout(): void + { + $this->client->request('GET', '/sitemap.xml'); + + self::assertStringContainsString(rawurlencode(AboutController::SLUG), $this->client->getResponse()->getContent()); + } +} diff --git a/tests/Shared/LandingPageTest.php b/tests/Shared/LandingPageTest.php index 76d6d33c..a58b6ff8 100644 --- a/tests/Shared/LandingPageTest.php +++ b/tests/Shared/LandingPageTest.php @@ -84,9 +84,9 @@ class LandingPageTest extends WebTestCase $xml = $this->html('/sitemap.xml'); $doc = new \SimpleXMLElement($xml); - // خانه + هر صفحهٔ فرود. عدد از خودِ رجیستری می‌آید تا افزودن خوشهٔ کلیدواژهٔ - // تازه این تست را نشکند، ولی جاافتادن یک صفحه از sitemap هنوز قرمز شود. - self::assertCount(1 + count($this->registry->all()), $doc->url); + // خانه + دربارهٔ ما + هر صفحهٔ فرود. عدد از خودِ رجیستری می‌آید تا افزودن خوشهٔ + // کلیدواژهٔ تازه این تست را نشکند، ولی جاافتادن یک صفحه از sitemap هنوز قرمز شود. + self::assertCount(2 + count($this->registry->all()), $doc->url); foreach (array_keys($this->registry->all()) as $slug) { self::assertStringContainsString(rawurlencode($slug), $xml, "«{$slug}» در sitemap نیست");