@extends('layouts.dashboard') @section('content') @php /** * Vendor advertising — new campaign form + visual placement map. * @var array $placements AdCampaign::placements [key => ['label','desc']] * @var array $prices [placement => monthly price] * @var array $tags [['name','slug'], ...] * @var array $cuisines [['name','slug'], ...] */ $oldVal = static function (string $k, string $def = '') { return (string) \App\Support\Session::old($k, $def); }; // Preselect a placement so the price + placement map are never empty on first open. // (Falls back to the first placement key when the form hasn't been submitted yet.) $placementKeys = array_keys($placements); $selPlacement = $oldVal('placement', (string) ($placementKeys[0] ?? '')); $currency = setting('currency_symbol', '$'); // Numeric price map for the live JS calculator. $priceMap = []; foreach ($prices as $k => $p) { $priceMap[$k] = (float) $p; } @endphp @php /* .qm-d2: the dashboard density standard (app.css §35) */ @endphp
@php /* Back rides the floating top bar, as on every detail/editor page — never inside a card. */ @endphp
{{ t_raw('common.back') }}

{{ t_raw('vendor.campaigns.form_heading') }}

@csrf
{{ t_raw('admin.campaigns.col_placement') }}
@php /* CHOOSE HERE, FILL BELOW. The whole campaign form used to be moved INTO whichever row was selected, so the seven priced options were split apart by a half-completed form and the owner had to scroll past their own typing to compare the two placements either side of it. Picking and filling are different jobs; the list stays a list. */ @endphp @foreach ($placements as $key => $p)
@endforeach
@php /* THE ONE FIELD BLOCK, in one place. Each part is shown only when the chosen placement actually renders it — the video band shows no headline and no body, the hero slide shows no body, and only the listing page targets a tag or cuisine — so nobody is asked to write copy that will be thrown away. */ @endphp
{{ t_raw('vendor.campaigns.creative_legend') }}
{!! media_field_html('image', null, ['accept' => 'both']) !!}
@php /* THE PRICE, BROKEN OUT. It read "Estimated total" and showed one number, which was the net — the gateway then took the platform's tax on top, so the figure the owner agreed to was not the figure they paid. Nothing is estimated here: the placement price and the months are both known, and Invoice::grossFor() is the same rule the charge itself uses (CampaignController). On an install that charges no platform tax the tax line simply does not draw. */ $pTax = \App\Services\Invoice::platformTax(); $pTaxOn = ($pTax['tax_mode'] ?? 'none') !== 'none' && (float) ($pTax['tax_rate'] ?? 0) > 0; $pTaxLabel = trim((string) ($pTax['tax_label'] ?? '')) ?: t_raw('checkout.tax'); @endphp
{{ t_raw('checkout.subtotal') }} {{ $currency }}0.00
@if ($pTaxOn)
{{ $pTaxLabel }} {{ $currency }}0.00
@endif
{{ t_raw('common.total') }} {{ $currency }}0.00
@php /* HOW it is paid for is no longer asked here. This form used to carry a "Pay with" choice, so the owner committed to Stripe or PayPal while the total was still moving as they changed placement and months — and the checkout page they landed on could then only render the one gateway that decision had locked in. The choice belongs beside the amount it applies to, so it is made on the checkout page, exactly as the plan flow does it. */ @endphp
{{ t_raw('common.cancel') }}
@php /* NOT h-100. The card was stretched to match the form column beside it, which is as tall as eight placement rows, so the little wireframe floated in a mostly empty card. It sits at its own height now and follows the reader down instead. */ @endphp

{{ t_raw('vendor.campaigns.map_heading') }}

{{ t_raw('vendor.campaigns.map_hint') }}

@php /* ONE PAGE AT A TIME. Both mock-ups drew at once, so an owner buying a home-page box was also shown the listing page they were not buying — two site diagrams competing to answer one question. The screen that holds the selected zone is the only one shown. */ @endphp
{{ t_raw('vendor.campaigns.map_zone_mega_menu') }}
{{ t_raw('vendor.campaigns.map_zone_hero_slider') }}
{{ t_raw('vendor.campaigns.map_zone_1x1_box') }}
{{ t_raw('vendor.campaigns.map_zone_home_card') }}
{{ t_raw('vendor.campaigns.map_zone_feature_video') }}
{{ t_raw('vendor.campaigns.map_zone_tall_2row') }}
{{ t_raw('vendor.campaigns.map_zone_tag_cuisine_banner') }}

{{ t_raw('vendor.campaigns.map_caption_listing_page') }}

@php /* HOW IT WILL LOOK, in the shape it will actually be drawn in. The map above answers WHERE on the site; this answers WHAT the customer sees. Seven placements share four shapes, and each is the storefront's own class — .qm-ad-card, .qm-ad-mega, .qm-videoband, .qm-heroslide — all of which app.css already ships to this page, so nothing here is a mock-up that can drift from the real thing. The picture follows the same fallback the renderer uses: the creative, then the restaurant cover, then the theme's fallback image. */ $pvCover = trim((string) ($previewCover ?? '')); $pvImg = $pvCover !== '' ? media($pvCover) : ad_fallback_src(); $pvName = trim((string) ($previewName ?? '')); @endphp

{{ t_raw('vendor.campaigns.preview_heading') }}

{{ t_raw('vendor.campaigns.preview_hint') }}

@php /* One shape is shown at a time; the rest stay in the DOM so switching placement is instant and needs no request. */ @endphp @php /* Media only — the real band renders no headline and no body (AdCampaign::fieldsFor). */ @endphp @php /* Media + headline; the hero splits the headline on a dash into two tones. */ @endphp
@php /* /.qm-d2 */ @endphp @endsection