From feafb9d19e2609ac3ec7b5cad38378aa92373b48 Mon Sep 17 00:00:00 2001 From: Yonas Tewabe Date: Tue, 30 Jun 2026 15:53:48 +0300 Subject: [PATCH 01/10] Update sync-env-from-server-jenkins.sh --- scripts/deploy/sync-env-from-server-jenkins.sh | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/scripts/deploy/sync-env-from-server-jenkins.sh b/scripts/deploy/sync-env-from-server-jenkins.sh index 74b9a3f13..e444996d6 100644 --- a/scripts/deploy/sync-env-from-server-jenkins.sh +++ b/scripts/deploy/sync-env-from-server-jenkins.sh @@ -12,24 +12,23 @@ # Server layout (one file per service): # /home/user/environmen///freight-api.env # /home/user/environmen///freight-portal.env - set -euo pipefail - DEPLOY_USER="${DEPLOY_USER:-tria}" BRANCH="${BRANCH:?BRANCH is required}" BRANCH_SLUG="${BRANCH_SLUG:-$(echo "${BRANCH}" | tr "[:upper:]" "[:lower:]" | sed -E "s/[^a-z0-9]+/-/g; s/^-+//; s/-+$//")}" ENV_ROOT="${ENV_ROOT:-/home/${DEPLOY_USER}/environment/edr/${BRANCH_SLUG}/${PROJECT:?PROJECT is required}}" CI_ENV_FILE="${CI_ENV_FILE:?CI_ENV_FILE is required (e.g. \${WORKSPACE}/.ci-env/.env)}" - if [[ ! -d "${ENV_ROOT}" ]]; then echo "Environment directory not found: ${ENV_ROOT}" >&2 exit 1 fi echo "Using environment directory: ${ENV_ROOT}" - mkdir -p "$(dirname "${CI_ENV_FILE}")" +if [[ -d "${CI_ENV_FILE}" ]]; then + echo "Removing stale directory at ${CI_ENV_FILE}" >&2 + rm -rf "${CI_ENV_FILE}" +fi : > "${CI_ENV_FILE}" - declare -A SERVICE_ENV_TARGET=( ["freight-api"]="apps/edr-freight-api/.env" ["freight-portal"]="apps/edr-freight-web/portal/.env" @@ -39,36 +38,29 @@ declare -A SERVICE_ENV_TARGET=( ["passenger-backoffice"]="apps/edr-passenger-web/backoffice/.env" ["payment-api"]="apps/edr-payment-api/.env" ) - for service in "$@"; do src="${ENV_ROOT}/${service}.env" dest="${SERVICE_ENV_TARGET[${service}]:-}" - if [[ -z "${dest}" ]]; then echo "Unknown service: ${service}" >&2 exit 1 fi - if [[ ! -f "${src}" ]]; then echo "Missing env file: ${src}" >&2 exit 1 fi - mkdir -p "$(dirname "${dest}")" cp "${src}" "${dest}" echo "Synced ${src} -> ${dest}" - port_value=$(sed -n -E 's/^[[:space:]]*PORT[[:space:]]*=[[:space:]]*"?([^"#]+)"?[[:space:]]*(#.*)?$/\1/p' "${src}" | head -n1 | tr -d '[:space:]') if [[ -z "${port_value}" ]]; then echo "Missing required PORT in env file: ${src}" >&2 exit 1 fi - service_var=$(echo "${service}" | tr '[:lower:]-' '[:upper:]_') echo "${service_var}_PORT=${port_value}" >> "${CI_ENV_FILE}" echo "Exported ${service_var}_PORT from ${src}" - # Forward NEXT_PUBLIC_* and VITE_* vars so docker compose build can inject them as build args. grep -E '^[[:space:]]*(NEXT_PUBLIC_|VITE_)[A-Za-z0-9_]+=' "${src}" \ | sed -E 's/^[[:space:]]*//' >> "${CI_ENV_FILE}" || true -done \ No newline at end of file +done From 1896c8d36c97fb5544606999652e6b585dec46b8 Mon Sep 17 00:00:00 2001 From: SennayT Date: Tue, 14 Jul 2026 00:15:24 +0300 Subject: [PATCH 02/10] remove skip for now button --- .../portal/src/app/booking/passengers/page.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/edr-passenger-web/portal/src/app/booking/passengers/page.tsx b/apps/edr-passenger-web/portal/src/app/booking/passengers/page.tsx index 4639bd196..bfbb621ad 100644 --- a/apps/edr-passenger-web/portal/src/app/booking/passengers/page.tsx +++ b/apps/edr-passenger-web/portal/src/app/booking/passengers/page.tsx @@ -1153,14 +1153,14 @@ function PassengersForm() { Finish verifying Passenger {(verifyingIndex ?? 0) + 1} first

)} - + */} ) : showManualEntryLink ? (
From 35eb4b37ac5d8edd6824d2f41b95b9c0102144a9 Mon Sep 17 00:00:00 2001 From: yonastewabe Date: Tue, 14 Jul 2026 09:06:43 +0300 Subject: [PATCH 03/10] feat(seo): Add metadata and SEO improvements to passenger portal --- .github/workflows/deploy.yml | 1 - .../portal/src/app/about/layout.tsx | 21 ++++ .../portal/src/app/contact/layout.tsx | 21 ++++ .../portal/src/app/guide/layout.tsx | 28 ++++++ .../portal/src/app/help/layout.tsx | 23 +++++ .../portal/src/app/layout.tsx | 97 ++++++++++++++++++- .../portal/src/app/packages/[id]/layout.tsx | 80 +++++++++++++++ .../portal/src/app/packages/layout.tsx | 23 +++++ .../edr-passenger-web/portal/src/app/page.tsx | 17 ++++ .../portal/src/app/robots.ts | 37 +++++++ .../portal/src/app/services/layout.tsx | 23 +++++ .../portal/src/app/sitemap.ts | 59 +++++++++++ .../portal/src/components/JsonLd.tsx | 12 +++ .../portal/src/middleware.ts | 27 ++++-- 14 files changed, 459 insertions(+), 10 deletions(-) create mode 100644 apps/edr-passenger-web/portal/src/app/about/layout.tsx create mode 100644 apps/edr-passenger-web/portal/src/app/contact/layout.tsx create mode 100644 apps/edr-passenger-web/portal/src/app/guide/layout.tsx create mode 100644 apps/edr-passenger-web/portal/src/app/help/layout.tsx create mode 100644 apps/edr-passenger-web/portal/src/app/packages/[id]/layout.tsx create mode 100644 apps/edr-passenger-web/portal/src/app/packages/layout.tsx create mode 100644 apps/edr-passenger-web/portal/src/app/robots.ts create mode 100644 apps/edr-passenger-web/portal/src/app/services/layout.tsx create mode 100644 apps/edr-passenger-web/portal/src/app/sitemap.ts create mode 100644 apps/edr-passenger-web/portal/src/components/JsonLd.tsx diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 057cb0c1b..f0beccd20 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -2,7 +2,6 @@ name: Deploy Stacks on: push: branches: - - main - dev - staging workflow_dispatch: diff --git a/apps/edr-passenger-web/portal/src/app/about/layout.tsx b/apps/edr-passenger-web/portal/src/app/about/layout.tsx new file mode 100644 index 000000000..a7bb1b25d --- /dev/null +++ b/apps/edr-passenger-web/portal/src/app/about/layout.tsx @@ -0,0 +1,21 @@ +import type { Metadata } from 'next'; + +export const metadata: Metadata = { + title: 'About EDR – Connecting East Africa by Rail', + description: + 'Learn about the Ethio-Djibouti Railway (EDR): our mission to connect Ethiopia and Djibouti with comfortable, affordable, and sustainable train travel.', + alternates: { + canonical: '/about', + }, + openGraph: { + title: 'About EDR – Connecting East Africa by Rail', + description: + 'Our mission is to provide reliable, affordable, and comfortable train travel connecting Ethiopia and Djibouti.', + url: '/about', + images: [{ url: '/edr-banner.jpg', width: 1200, height: 630, alt: 'EDR Railway – About Us' }], + }, +}; + +export default function AboutLayout({ children }: { children: React.ReactNode }) { + return children; +} diff --git a/apps/edr-passenger-web/portal/src/app/contact/layout.tsx b/apps/edr-passenger-web/portal/src/app/contact/layout.tsx new file mode 100644 index 000000000..3a5c61836 --- /dev/null +++ b/apps/edr-passenger-web/portal/src/app/contact/layout.tsx @@ -0,0 +1,21 @@ +import type { Metadata } from 'next'; + +export const metadata: Metadata = { + title: 'Contact EDR – Get in Touch', + description: + 'Contact the Ethio-Djibouti Railway (EDR) support team. We are available to assist with your train journey.', + alternates: { + canonical: '/contact', + }, + openGraph: { + title: 'Contact EDR – Get in Touch', + description: + 'Reach the EDR support team by phone, email, or in person. We are available to assist with your train journey.', + url: '/contact', + images: [{ url: '/edr-banner.jpg', width: 1200, height: 630, alt: 'EDR Railway – Contact Us' }], + }, +}; + +export default function ContactLayout({ children }: { children: React.ReactNode }) { + return children; +} diff --git a/apps/edr-passenger-web/portal/src/app/guide/layout.tsx b/apps/edr-passenger-web/portal/src/app/guide/layout.tsx new file mode 100644 index 000000000..417c46cf3 --- /dev/null +++ b/apps/edr-passenger-web/portal/src/app/guide/layout.tsx @@ -0,0 +1,28 @@ +import type { Metadata } from 'next'; + +export const metadata: Metadata = { + title: 'How to Book a Train Ticket – EDR Step-by-Step Guide', + description: + 'Step-by-step guide to booking an EDR train ticket online: search trains, select your seat class, enter passenger details, and complete payment.', + alternates: { + canonical: '/guide', + }, + openGraph: { + title: 'How to Book a Train Ticket – EDR Step-by-Step Guide', + description: + 'Follow our simple guide to book your EDR train journey in minutes.', + url: '/guide', + images: [ + { + url: '/edr-banner.jpg', + width: 1200, + height: 630, + alt: 'EDR Railway – How to Book a Train Ticket', + }, + ], + }, +}; + +export default function GuideLayout({ children }: { children: React.ReactNode }) { + return children; +} diff --git a/apps/edr-passenger-web/portal/src/app/help/layout.tsx b/apps/edr-passenger-web/portal/src/app/help/layout.tsx new file mode 100644 index 000000000..0211d6d23 --- /dev/null +++ b/apps/edr-passenger-web/portal/src/app/help/layout.tsx @@ -0,0 +1,23 @@ +import type { Metadata } from 'next'; + +export const metadata: Metadata = { + title: 'Help & FAQs – EDR Train Booking', + description: + 'Find answers to common questions about booking EDR train tickets: how to book, passenger pricing, identity verification, seat classes, payment methods, and more.', + alternates: { + canonical: '/help', + }, + openGraph: { + title: 'Help & FAQs – EDR Train Booking', + description: + 'Answers to your questions about booking EDR train tickets, payment methods, identity verification, and seat selection.', + url: '/help', + images: [ + { url: '/edr-banner.jpg', width: 1200, height: 630, alt: 'EDR Railway – Help & FAQs' }, + ], + }, +}; + +export default function HelpLayout({ children }: { children: React.ReactNode }) { + return children; +} diff --git a/apps/edr-passenger-web/portal/src/app/layout.tsx b/apps/edr-passenger-web/portal/src/app/layout.tsx index 1128124e3..a6d5c787f 100644 --- a/apps/edr-passenger-web/portal/src/app/layout.tsx +++ b/apps/edr-passenger-web/portal/src/app/layout.tsx @@ -7,10 +7,61 @@ import MobileTopBar from '@/components/MobileTopBar'; import BottomTabBar from '@/components/BottomTabBar'; import { LoadingIndicator } from '@/components/LoadingIndicator'; import SupportWidget from '@/features/support/SupportWidgetLazy'; +import { JsonLd } from '@/components/JsonLd'; + +const siteUrl = process.env.NEXT_PUBLIC_SITE_URL ?? 'https://passenger.edrsc.com'; export const metadata: Metadata = { - title: 'EDR Passenger Portal - Book your train journey', - description: 'Book train tickets on the Ethio-Djibouti Railway', + metadataBase: new URL(siteUrl), + title: { + default: 'EDR Passenger Portal – Book Train Tickets Online', + template: '%s | EDR Passenger Portal', + }, + description: + 'Book train tickets on the Ethio-Djibouti Railway. Travel between Ethiopia and Djibouti with easy online booking, seat selection, and multiple payment options.', + authors: [{ name: 'EDR – Ethio-Djibouti Railway' }], + creator: 'EDR – Ethio-Djibouti Railway', + publisher: 'EDR – Ethio-Djibouti Railway', + robots: { + index: true, + follow: true, + googleBot: { + index: true, + follow: true, + 'max-snippet': -1, + 'max-image-preview': 'large', + 'max-video-preview': -1, + }, + }, + openGraph: { + type: 'website', + locale: 'en_US', + url: siteUrl, + siteName: 'EDR Passenger Portal', + title: 'EDR Passenger Portal – Book Train Tickets Online', + description: + 'Book train tickets on the Ethio-Djibouti Railway. Comfortable seats, flexible payment options, and easy online booking.', + images: [ + { + url: '/edr-banner.jpg', + width: 1200, + height: 630, + alt: 'EDR Ethio-Djibouti Railway – Book your train journey', + }, + ], + }, + twitter: { + card: 'summary_large_image', + title: 'EDR Passenger Portal – Book Train Tickets Online', + description: + 'Book train tickets on the Ethio-Djibouti Railway. Comfortable seats, flexible payment options, and easy online booking.', + images: ['/edr-banner.jpg'], + }, + icons: { + icon: '/edr-logo.png', + shortcut: '/edr-logo.png', + apple: '/edr-logo.png', + }, }; export default function RootLayout({ @@ -20,8 +71,48 @@ export default function RootLayout({ }) { // Nonce set per-request by middleware; required for this inline script under the CSP. const nonce = headers().get('x-nonce') ?? undefined; + + const organizationSchema = { + '@context': 'https://schema.org', + '@type': 'Organization', + name: 'Ethio-Djibouti Railway (EDR)', + url: siteUrl, + logo: `${siteUrl}/edr-logo.png`, + contactPoint: { + '@type': 'ContactPoint', + telephone: '9546', + contactType: 'customer service', + availableLanguage: ['English', 'Amharic'], + }, + address: { + '@type': 'PostalAddress', + addressLocality: 'Addis Ababa', + addressCountry: 'ET', + }, + sameAs: [], + }; + + const websiteSchema = { + '@context': 'https://schema.org', + '@type': 'WebSite', + name: 'EDR Passenger Portal', + url: siteUrl, + potentialAction: { + '@type': 'SearchAction', + target: { + '@type': 'EntryPoint', + urlTemplate: `${siteUrl}/booking/search?q={search_term_string}`, + }, + 'query-input': 'required name=search_term_string', + }, + }; + return ( - + + + + +