# LandingPage Module Documentation

## 1. Introduction

The LandingPage module provides a comprehensive system for creating, managing, and customizing landing pages within your Laravel application. It features a dynamic section builder, theme support, menu management, and integration with Google Analytics. Its goal is to offer a flexible way to present content and can be extended to display data from other parts of your application.

## 2. Installation & Setup

Installation: It's assumed this module is installed via your application's main module management system (e.g., by uploading a ZIP in the admin panel or via Composer if it were a standalone package).

Migrations: After installation, run database migrations:

    php artisan module:migrate LandingPage

Configuration:

- Homepage Slug: Define which page slug serves as the site's homepage via the `landingpage_homepage_slug` setting (typically in your application's main settings table, defaulting to 'home'). This is managed under "Landing Page" → "Theme Settings" in the admin panel.
- Default Theme: The active theme is managed under "Landing Page" → "Theme Settings" in the admin panel.

## 3. Core Features

### 3.1. Page Management (`LpPageController`)

- CRUD Operations: Create, read, update, and delete landing pages.
- Content Fields: Each page has a title, slug (auto-generated or custom), main content (WYSIWYG editor for fallback/default content), and optional default hero section fields (title, subtitle, CTA).
- SEO Settings: Meta title, meta description, and meta keywords per page.
- Publishing: Pages can be in "Published" or "Draft" status.
- Sort Order: Control the order of pages.
- Theme Templates: Assign specific Blade templates from the active theme to individual pages for varied layouts.

### 3.2. Dynamic Section Builder (`LpPageController`, JavaScript)

Pages are constructed using dynamic sections. Admins can add, remove, and reorder sections on the page edit screen.

#### Available Section Types:

- Hero Section: Full-width banner with titles, subtitles, CTAs, and background images. Supports multiple slides.
- Services Overview: Display services with titles, descriptions, icons, or images.
- Team Members: Introduce team members with names, titles, images, and social links.
- Testimonials: Display customer quotes, authors, and author images.
- Contact CTA: A call-to-action section.
- Featured Companies: Highlights companies marked as featured from the `BusinessDirectory` module. (Uses `themes/job_board/sections/featured_companies.blade.php`)
- Featured Products: Showcases products marked as featured from the `BusinessDirectory` module. (Uses `themes/job_board/sections/featured_products.blade.php`)
- Featured Jobs: Displays job openings marked as featured from the `BusinessDirectory` module. (Uses `themes/job_board/sections/featured_jobs.blade.php`)
- Featured Tenders: Lists tenders marked as featured from the `BusinessDirectory` module. (Uses `themes/job_board/sections/featured_tenders.blade.php`)
- Legacy Integrations (can be adapted):
  - Company Projects (Business Directory)
- Our Portfolio (DigitalVocano): Showcases your own company's projects from the `DigitalVocano` module.
- Custom HTML: Allows embedding raw HTML content via a WYSIWYG editor.

#### Content Configuration:

Each section type has its own set of fields. Image uploads are supported for Hero slides, Services items, Team member photos, and Testimonial author images. The `LpPageController::update()` method handles storing these images in `storage/app/public/landingpage/...`.

#### Frontend Rendering & Data Fetching (`LandingPageSection` Component & Section Partials):

The `<x-landingpage::landing-page-section :section="$section" :activeTheme="$activeTheme" :businessData="$businessData" />` Blade component dynamically includes the appropriate Blade partial from the active theme's `sections` directory (e.g., `themes/job_board/sections/hero.blade.php`) based on the section's type. The `Modules\LandingPage\View\Components\LandingPageSection.php` class passes the section's content (`$section->content`) as `$content` to the partial. For sections requiring dynamic data (like "Featured Companies"), this data is typically fetched by `FrontendPageController::getBusinessDataForPage()` and passed to the main page view, then made available to the section partial. See "Data Flow for Featured Content Sections" for details.

### 3.3. Menu Management (`MenuController`, `MenuItemController`)

- Create and manage multiple menus (e.g., "Main Navigation", "Footer Links").
- Add menu items linking to:
  - Landing Pages: Select from existing published pages.
  - Custom URLs: External or internal absolute URLs.
  - Named Routes: Link to specific Laravel routes.
  - List Company: (Typically a named route or custom URL for users to list their company).
  - Post Products: (Typically a named route or custom URL for users to post products).
  - Post Tender: (Typically a named route or custom URL for users to post tenders).
- Hierarchy & Ordering: Menu items can be nested. Order is managed via a drag-and-drop interface (using SortableJS).

### 3.4. Theme System (`ThemeSettingController`)

Themes are located in `Modules/LandingPage/Resources/views/themes/`. Each theme has its own subdirectory.

#### Theme Structure:

- `layouts/app.blade.php`: Main layout file for most pages.
- `layouts/master.blade.php`: (Optional) Alternative main layout, often used for specific page types like single product views if a different overall structure is needed.
- `partials/header.blade.php`, `partials/footer.blade.php`: Reusable components.
- `sections/`: Blade partials for each dynamic section type.
- `templates/`: Optional directory for page-specific templates.
- `page.blade.php`: Default view for rendering `LpPage` content and its sections.
- `home.blade.php`: (Optional) A dedicated view for the homepage if it requires a structure different from `page.blade.php`.
- `page_not_found.blade.php`: View for 404 errors.
- Assets (CSS, JS, Images): Typically managed via Vite and linked in `layouts/app.blade.php`, but can also include theme-specific static assets.

The active theme is selected in the admin panel ("Landing Page" → "Theme Settings"). New themes, compatible with the DigitalVocano boilerplate, can be installed by uploading a ZIP package. The `PublicPageController` and `LandingPageSection` component use this setting for rendering.

#### Theme: `job_board`

The `job_board` theme is a specialized theme provided with this module. Its key files include:

- Layouts: `layouts/app.blade.php` (main application layout with dark mode, SEO, Vite integration), `layouts/master.blade.php` (used by some single item templates).
- Partials: `partials/topbar.blade.php`, `partials/header.blade.php`, `partials/footer.blade.php`.
- Page Renderers: `page.blade.php` (default for LpPages), `page_not_found.blade.php`.
- Section Partials (`sections/`):
  - `hero.blade.php`, `services.blade.php`, etc. (standard sections)
  - `featured_companies.blade.php`, `featured_products.blade.php`, `featured_jobs.blade.php`, `featured_tenders.blade.php`: These expect `$content` (from section settings) and a corresponding data variable (e.g., `$featured_companies_data`) passed from the controller via `$businessData`.
- Templates (`templates/`): For single item views like `company_single.blade.php`, `job_single.blade.php`, `product_single.blade.php`, `tender_single.blade.php`, `news_single.blade.php`. Also includes listing pages for company-specific items: `company_products_listing.blade.php`, `company_jobs_listing.blade.php`, `company_tenders_listing.blade.php`.

### 3.5. Google Analytics Integration (`ThemeSettingController`, `GoogleAnalyticsService`)

#### Configuration:

In "Theme Settings", admins can:

- Enable/disable GA tracking.
- Enter GA4 Measurement ID (e.g., `G-XXXXXXXXXX`).
- Enter GA4 Property ID (numeric, for fetching stats).
- Provide the server path to the Google Service Account credentials JSON file.
- A "How-To" guide is included on the settings page.

#### Frontend Tracking:

If enabled, the GA4 `gtag.js` snippet is injected into the `<head>` of frontend pages.

#### Statistics Display:

- LandingPage Dashboard: Shows basic stats (Users, Page Views, Sessions) and Top Pages.
- Main Admin Dashboard: Conditionally displays the same GA summary if the module is active and GA is configured.

#### Data Fetching:

The `Modules\LandingPage\Services\GoogleAnalyticsService.php` class uses the `google/analytics-data` package to communicate with the Google Analytics Data API V1. It caches API responses.

## New: Data Flow for Featured Content Sections

The "Featured" sections (e.g., Featured Companies, Featured Products) display dynamic content from other modules, typically items marked with an `is_featured` flag. Here's how the data flows:

1. Admin Configuration: An admin adds a "Featured Companies" section to an `LpPage` via the page builder. They configure settings like the section title, number of items to show (e.g., `items_to_show: 4`). These settings are saved in the `LpPageSection->content` JSON field.
2. Page Request & Controller Action: A user visits the page. The request is handled by `FrontendPageController::show()`.
3. Business Data Fetching: `FrontendPageController::show()` calls its protected method `getBusinessDataForPage(LpPage $page, string $activeTheme)`.
4. Identifying Section Needs: Inside `getBusinessDataForPage()`, the code iterates through `$page->sections`. If it finds a section of type `featured_companies`, it proceeds to fetch the data.

       // Simplified example from FrontendPageController::getBusinessDataForPage()
       foreach ($page->sections as $section) {
           if ($section->type === 'featured_companies' && !isset($data['featured_companies_data'])) {
               $itemsToShow = (int) ($section->content['items_to_show'] ?? 4);
               $data['featured_companies_data'] = \Modules\BusinessDirectory\Entities\Company::where('is_featured', true)
                                                               ->where('status', 'approved')
                                                               ->latest()->take($itemsToShow)->get();
           }
           // ... similar logic for other featured types ...
       }

5. Passing Data to View: The `$businessData` array (now containing `$featured_companies_data`) is passed to the main page view (e.g., `themes/job_board/page.blade.php`) along with `$page` and `$activeTheme`.
6. Section Component Rendering: The main page view iterates through `$page->sections` and uses the `<x-landingpage::landing-page-section :section="$section" :activeTheme="$activeTheme" :businessData="$businessData" />` component.

   Important: The `$businessData` array must be passed to the component.

7. Component Logic (`LandingPageSection.php`): The `render()` method of the `LandingPageSection` component receives `$section` and `$businessData`. It determines the correct partial (e.g., `featured_companies.blade.php`). It makes `$section->content` available as `$content` to the partial. It also needs to extract the relevant data from `$businessData` (e.g., `$businessData['featured_companies_data']`) and pass it to the partial under the expected variable name (e.g., as `$featured_companies_data`).

       // Simplified logic in LandingPageSection::render()
       public function render()
       {
           $viewName = "landingpage::themes.{$this->activeTheme}.sections.{$this->section->type}";
           $viewData = [
               'section' => $this->section,
               'content' => $this->section->content, // Already available as $content in partial
               'activeTheme' => $this->activeTheme,
           ];

           // Pass specific data from businessData based on section type
           $dataKey = $this->section->type . '_data'; // e.g., 'featured_companies_data'
           if (isset($this->businessData[$dataKey])) {
               $viewData[$dataKey] = $this->businessData[$dataKey];
           }

           return view($viewName, $viewData);
       }

8. Partial Rendering: The section partial (e.g., `themes/job_board/sections/featured_companies.blade.php`) now has access to `$content` (for its settings) and `$featured_companies_data` (for the items to display) and renders the HTML.

## 4. How the LandingPage Module Interacts with Other Data/Modules

The LandingPage module is primarily a content presentation system. It can be configured to display data from other modules.

### 4.1. Integrating External Module Data into Dynamic Sections

1. Define a New Section Type: Add a unique key and display name to `$sectionTypes` in `LpPageController@edit`.
2. Admin Configuration Fields: In `edit.blade.php` (JavaScript `renderContentFields` function), add a `case` for your new section type and generate HTML for its admin fields (e.g., multi-selects, number inputs).
3. Data Saving: The configuration from the admin fields (e.g., section title, number of items) is saved in the section's JSON `content` by `LpPageController@update`.
4. Create Frontend Rendering Partial: In your active theme (e.g., `themes/general/sections/your_section_type.blade.php`), create a new Blade file. This partial receives `$section` and its `$content`.

   For simple sections, you might query directly in the partial. However, for more complex data or to keep partials cleaner, it's recommended to fetch data in `FrontendPageController::getBusinessDataForPage()` and pass it via `$businessData` as described in the "Data Flow for Featured Content Sections" above.

       <!-- Example: themes/general/sections/portfolio-projects.blade.php -->
       @php
           $sectionTitle = $section->content['title'] ?? 'Our Recent Work';
           $numberOfProjects = (int)($section->content['number_of_items'] ?? 3);

           $portfolioProjects = \Modules\DigitalVocano\Entities\Project::query()
               // ->where('is_published', true) // Example criteria
               // ->orderBy('sort_order', 'asc')
               // ->take($numberOfProjects)
               // ->get();
           // Recommended: $portfolioProjects = $portfolio_projects_data ?? collect(); (assuming data passed via $businessData)
       @endphp

       @if($portfolioProjects->isNotEmpty())
           <section class="portfolio-section">
               <h2>{{ $sectionTitle }}</h2>
               <div class="project-grid">
                   @foreach($portfolioProjects as $dvProject)
                       <div class="project-card">
                           <h3>{{ $dvProject->name }}</h3>
                           <!-- ... more project details ... -->
                       </div>
                   @endforeach
               </div>
           </section>
       @endif

5. Automatic Rendering: The `<x-landingpage::landing-page-section>` component automatically includes your new section partial based on its type.

Key Principle: The LandingPage module stores references or configurations for displaying data from other modules. The actual data fetching from those other modules typically happens in `FrontendPageController::getBusinessDataForPage()` and is then passed to the theme's specific section partials for rendering.

### 4.2. Creating New Dedicated Listing Pages (e.g., /jobs, /portfolio)

To create entirely new pages that list all items of a certain type from another module (e.g., a page at `/jobs` to show all job listings), follow these steps:

1. Define a Route: In `Modules/LandingPage/routes/web.php`, add a new route. Make sure it's placed before the generic `/{slug?}` catch-all route.

       // Example for a new "/portfolio" page
       Route::get('/portfolio', [PublicPageController::class, 'showPortfolioProjects'])->name('landingpage.portfolio.index');

2. Create a Controller Method: In `Modules/LandingPage/Http/Controllers/PublicPageController.php` (for general listings like all jobs, all products) or `Modules/LandingPage/Http/Controllers/FrontendController.php` (for company-specific listings like all products of a specific company), add a new public method. This method will:
   - Fetch the required data from the other module's entities (e.g., `\Modules\DigitalVocano\Entities\Project::where('is_published', true)->paginate(10);`).
   - Pass any necessary data (like page title, meta description, and the fetched items) to a new view.

       // Example method in PublicPageController.php for a general portfolio page
       public function showPortfolioProjects(Request $request)
       {
           $activeTheme = setting('landingpage_active_theme', 'general');
           $portfolioProjects = \Modules\DigitalVocano\Entities\Project::where('is_published', true)->orderBy('sort_order', 'asc')->paginate(9);
           $pageTitle = 'Our Portfolio';
           return view("landingpage::themes.{$activeTheme}.portfolio", compact('portfolioProjects', 'pageTitle', 'activeTheme'));
       }

       // Example method in FrontendController.php for company-specific products
       public function showCompanyProducts($company_slug)
       {
           $company = \Modules\BusinessDirectory\Entities\Company::where('slug', $company_slug)->firstOrFail();
           $activeTheme = setting('landingpage_active_theme', 'general');
           $products = $company->products()->where('status', 'published')->paginate(12);
           $page = (object) ['title' => 'Products from ' . $company->name, /* ... other meta ... */];
           return view("landingpage::themes.{$activeTheme}.templates.company_products_listing", compact('company', 'products', 'page', 'activeTheme'));
       }

3. Create a Blade View: In your active theme's directory (e.g., `Modules/LandingPage/Resources/views/themes/job_board/` or `themes/job_board/templates/`), create a new Blade file for your page (e.g., `portfolio.blade.php` or `templates/company_products_listing.blade.php`). This view will extend your theme's layout and display the fetched items, including pagination links if used.
4. (Optional) Add to Menu: Use the Menu Management system in the admin panel to add a link to your new page (e.g., using the route name `landingpage.portfolio.index` or the direct URL `/portfolio`).

### 4.3. Summary of Implemented Integrations:

Following the general approach, the module now integrates with:

- `BusinessDirectory` Module:
  - Featured Companies Section: Displays featured `Company` entities. (Partial: `sections/featured_companies.blade.php`)
  - Featured Products Section: Displays featured `Product` entities. (Partial: `sections/featured_products.blade.php`)
  - Featured Jobs Section: Displays featured `Job` entities. (Partial: `sections/featured_jobs.blade.php`)
  - Featured Tenders Section: Displays featured `Tender` entities. (Partial: `sections/featured_tenders.blade.php`)
  - Company Profile Page (`theme.company.show`): Displays details of a single company, including its products, jobs, and tenders. (Template: `templates/company_single.blade.php` or `BusinessDirectory::frontend.companies.profile`)
  - "View All" Company Items: Pages to list all products (`theme.company.products`), jobs (`theme.company.jobs`), or tenders (`theme.company.tenders`) for a specific company. (Templates: `templates/company_products_listing.blade.php`, etc.)
- `DigitalVocano` Module:
  - Our Portfolio: Fetches from `Modules\DigitalVocano\Entities\Project`.

Dedicated listing pages for general content (e.g., all jobs via `/jobs`, all products via `/products`) are handled by `PublicPageController.php` and corresponding theme views (e.g., `themes/job_board/jobs.blade.php` - if created).

## 5. Customization & Development

### 5.1. Creating New Themes

1. Develop your theme, ideally based on or compatible with the DigitalVocano boilerplate to ensure structural consistency.
2. Modify `layouts/app.blade.php`, `partials/header.blade.php`, `partials/footer.blade.php`.
3. Customize CSS (e.g., in `themes/my-new-theme/css/theme.css` or integrate with Vite).
4. Override or create new section partials in `themes/my-new-theme/sections/`.
5. Package your theme files (including a `theme.json` manifest if required by the installer) into a ZIP file.
6. Install the theme via the "Theme Settings" page in the LandingPage module's admin section by uploading the ZIP file.

### 5.2. Creating New Section Types

1. Define Type Key: Choose a unique string (e.g., `image-gallery`).
2. Admin Fields: Add a `case` in the `renderContentFields` JavaScript function (`admin/pages/edit.blade.php`) to define HTML for input fields.
3. Data Handling (Controller): If special data processing is needed (e.g., image uploads), update `LpPageController@update`.
4. Frontend Partial: Create a Blade file (e.g., `image-gallery.blade.php`) in `themes/[your-active-theme]/sections/`. This file receives `$section` and `$content`.

## 6. Important Files & Controllers

#### Controllers (Admin):

- `Modules/LandingPage/Http/Controllers/Admin/LpPageController.php`
- `Modules/LandingPage/Http/Controllers/Admin/MenuController.php`
- `Modules/LandingPage/Http/Controllers/Admin/MenuItemController.php`
- `Modules/LandingPage/Http/Controllers/Admin/ThemeSettingController.php`

#### Controller (Frontend):

- `Modules/LandingPage/Http/Controllers/FrontendPageController.php`: Responsible for rendering `LpPage` entities (dynamic pages built with sections). It determines the active theme, fetches the `LpPage` model, and calls `getBusinessDataForPage()` to gather any additional data required by the page's sections (like featured items). It then selects the appropriate theme view (e.g., `page.blade.php` or a custom template) for rendering.
- `Modules/LandingPage/Http/Controllers/FrontendController.php`: Handles displaying single detail pages for entities like individual jobs (`showJob`), companies (`showCompany`), products (`showProduct`), tenders (`showTender`), and news articles (`showNewsArticle`). It also manages the "View All" listing pages for items belonging to a specific company (e.g., `showCompanyProducts`, `showCompanyJobs`).
- `Modules/LandingPage/Http/Controllers/PublicPageController.php`: (Legacy/Alternative) Can be used for general listing pages that are not tied to a specific `LpPage` entity, such as a page listing all jobs (`/jobs`) or all products (`/products`) across the site. The current `web.php` routes point these general listing pages to this controller.

#### Services:

- `Modules/LandingPage/Services/GoogleAnalyticsService.php`

#### Entities (Models):

- `Modules/LandingPage/Entities/LpPage.php`
- `Modules/LandingPage/Entities/LpPageSection.php`
- `Modules/LandingPage/Entities/Menu.php`
- `Modules/LandingPage/Entities/MenuItem.php`

#### Core Views (Admin):

- `Modules/LandingPage/resources/views/admin/pages/index.blade.php` (Dashboard & List)
- `Modules/LandingPage/resources/views/admin/pages/edit.blade.php` (Page Builder)
- `Modules/LandingPage/resources/views/admin/menus/edit.blade.php` (Menu Management)
- `Modules/LandingPage/resources/views/admin/theme_settings/edit.blade.php` (Theme & GA Settings)

#### Core Views (Frontend - Theme Specific):

Example for `job_board` theme:

- `themes/job_board/layouts/app.blade.php` (Main Layout)
- `themes/job_board/page.blade.php` (Default renderer for LpPages)
- `themes/job_board/partials/` (header.blade.php, footer.blade.php, topbar.blade.php)
- `themes/job_board/sections/` (hero.blade.php, featured_companies.blade.php, etc.)
- `themes/job_board/templates/` (company_single.blade.php, job_single.blade.php, company_products_listing.blade.php, etc.)

#### Blade Component:

- Class: `Modules/LandingPage/View/Components/LandingPageSection.php`
- Invoked as: `<x-landingpage::landing-page-section :section="$section" :activeTheme="$activeTheme" :businessData="$businessData" />`
- This component is responsible for:
  - Determining the correct Blade partial for the section based on `$section->type` and `$activeTheme`.
  - Passing `$section->content` as `$content` to the partial.
  - Passing the relevant data from the `$businessData` array to the partial (e.g., `$featured_companies_data`).

## 7. Deep Dive: The Hero Section

The "Hero Section" is a prominent feature, designed for strong visual impact at the top of landing pages. It supports multiple slides, each configurable with:

- Slide Title: Main heading.
- Slide Subtitle: Supporting text.
- CTA Text & Link: Call to action button.
- Background Image: Supports direct uploads.

On the frontend, it's typically rendered using a JavaScript slider library (like Swiper.js) within the theme's `sections/hero.blade.php` partial.

The `LpPage` model also has "Default Hero Section" fields (`hero_title`, `hero_subtitle`, etc.) which can serve as a fallback if no dynamic "Hero Section" is added to a page, or if the theme is designed to use them.

Note: The appearance and behavior of the Hero Section depend heavily on the HTML and CSS in your active theme's `hero.blade.php` partial.

## 8. Google Analytics Setup Summary

To enable Google Analytics statistics display, you need to configure it correctly:

1. Google Cloud Project & API: Create/select a project in Google Cloud Console and enable the "Google Analytics Data API".
2. Service Account: Create a Service Account, grant it the "Analytics Reader" role, and download its JSON key.
3. Add Service Account to GA4: In your GA4 Property settings, add the service account's email as a user with "Viewer" permissions.
4. Store Credentials & Configure Path: Securely store the downloaded JSON key file on your server (e.g., `storage/app/google-analytics/service-account-credentials.json`). Important: Add this path to your `.gitignore`. Enter the full, absolute path to this JSON file in the "Service Account Credentials JSON Path" field in the LandingPage Theme Settings.
5. Enter IDs: Fill in your "Google Analytics Measurement ID" (e.g., G-XXXXXXXXXX) and "Google Analytics Property ID" (numeric) in the Theme Settings.

Detailed steps are available on the "Theme Settings" page within the admin panel of the LandingPage module.

## 9. Composer Dependencies

For Google Analytics data fetching, this module relies on the `google/analytics-data` package. Ensure it's installed in your main project:

    composer require google/analytics-data

The module's own `composer.json` (`Modules/LandingPage/composer.json`) primarily defines its PSR-4 autoloading and doesn't list external dependencies, as those are expected to be managed by the main application's `composer.json`.

## 10. Routing

#### Frontend Routes (`Modules/LandingPage/routes/web.php`):

    // General listing pages (handled by PublicPageController)
    Route::get('/jobs', [PublicPageController::class, 'showJobs'])->name('landingpage.jobs.index');
    Route::get('/products', [PublicPageController::class, 'showProducts'])->name('landingpage.products.index');
    Route::get('/tenders', [PublicPageController::class, 'showTenders'])->name('landingpage.tenders.index');
    Route::get('/companies', [PublicPageController::class, 'showCompanies'])->name('landingpage.companies.index');
    Route::get('/portfolio', [PublicPageController::class, 'showPortfolioProjects'])->name('landingpage.portfolio.index');
    Route::get('/news', [PublicPageController::class, 'showNews'])->name('landingpage.news.index');

    // Single item detail pages (handled by FrontendController)
    Route::get('/jobs/{slug}', [FrontendController::class, 'showJob'])->name('theme.job.show');
    Route::get('/companies/{slug}', [FrontendController::class, 'showCompany'])->name('theme.company.show');
    Route::get('/products/{slug}', [FrontendController::class, 'showProduct'])->name('theme.product.show');
    Route::get('/tenders/{slug}', [FrontendController::class, 'showTender'])->name('theme.tender.show');
    Route::get('/news/{slug}', [FrontendController::class, 'showNewsArticle'])->name('theme.news.show');

    // "View All" pages for specific company's items (handled by FrontendController)
    Route::get('/company/{company_slug}/products', [FrontendController::class, 'showCompanyProducts'])->name('theme.company.products');
    Route::get('/company/{company_slug}/jobs', [FrontendController::class, 'showCompanyJobs'])->name('theme.company.jobs');
    Route::get('/company/{company_slug}/tenders', [FrontendController::class, 'showCompanyTenders'])->name('theme.company.tenders');

    // Catch-all for dynamic pages
    Route::get('/{slug?}', [PublicPageController::class, 'showPage'])
        ->where('slug', '(.*)')
        ->name('landingpage.page.show');

This is a catch-all route and should ideally be one of the last routes registered in your application to avoid conflicts.

The `FrontendPageController` is responsible for handling the catch-all `/{slug?}` route to display dynamic `LpPage` entities. The `PublicPageController` handles predefined listing pages like `/jobs`. The `FrontendController` handles single item detail views and company-specific listings.

#### Admin Routes (`Modules/LandingPage/routes/admin.php`):

These routes are typically prefixed with `/admin/landingpage/` (or similar, depending on your main application's admin route group).

    Route::resource('pages', LpPageController::class);
    Route::get('theme-settings', [ThemeSettingController::class, 'edit'])->name('theme.settings.edit');
    Route::put('theme-settings', [ThemeSettingController::class, 'update'])->name('theme.settings.update');
    Route::resource('menus', MenuController::class);
    Route::post('menus/{menu}/items', [MenuItemController::class, 'store'])->name('menus.items.store');
    Route::put('menus/{menu}/items/{item}', [MenuItemController::class, 'update'])->name('menus.items.update');
    Route::delete('menus/{menu}/items/{item}', [MenuItemController::class, 'destroy'])->name('menus.items.destroy');
    Route::post('menus/{menu}/items/reorder', [MenuItemController::class, 'reorder'])->name('menus.items.reorder');

_N/A_