@extends('layouts.public') @section('content') @php /** @var array $plans @var array $stats @var array $partnerSpotlights */ $cur = setting('currency_symbol', '$'); $cycleMap = [ 'monthly' => t_raw('partner.cycle_monthly'), 'yearly' => t_raw('partner.cycle_yearly'), 'lifetime' => t_raw('partner.cycle_lifetime'), ]; // The plan we visually highlight as "Most popular" (the first paid tier). $popularSlug = ''; foreach ($plans as $p) { if ((float) $p['price'] > 0) { $popularSlug = (string) $p['slug']; break; } } // Icons resolve through t() like the words beside them, so a benefit is editable end to end rather // than being five-sixths editable with a glyph nobody can reach. $benefits = []; for ($bN = 1; $bN <= 6; $bN++) { $benefits[] = [ t_raw('partner.benefit' . $bN . '_icon'), t_raw('partner.benefit' . $bN . '_title'), t_raw('partner.benefit' . $bN . '_text'), ]; } // This page's OWN three steps — how a RESTAURANT joins — written on its content editor beside its // other sections. They used to be the customer's ordering steps shared from Settings → Business // model, so the page that recruits restaurants described the diner's journey back to them. Two // different processes, two different audiences, and two different layouts to draw them in. // // A step cleared of both its lines is a step the operator has taken off the page, so it is dropped // rather than drawn as an empty numbered bubble — and the ones left renumber, because "step 1, // step 3" describes a process with a hole in it. $steps = []; for ($pS = 1; $pS <= 3; $pS++) { $pTitle = trim(t_raw('partner.step' . $pS . '_title')); $pText = trim(t_raw('partner.step' . $pS . '_text')); if ($pTitle === '' && $pText === '') { continue; } $steps[] = [(string) (count($steps) + 1), $pTitle, $pText]; } $pHowEyebrow = trim(t_raw('partner.how_eyebrow')); $pHowTitle = trim(t_raw('partner.how_title')); /* * What a restaurant would actually be operating here. * * The benefits above say why to join; this says what you get. Each row is one of the * services the platform switches on in Settings → Business model, so a service the * operator turned off is not advertised to people it will not be given to — the page * and the switches can never disagree. * * The eyebrow comes from Capability::label() rather than a key of its own, so a section * is always named exactly what the switch that governs it is named. The two entries with * no switch behind them (the online storefront and languages) carry their own. * * An empty capability means the row always shows. The online-storefront row is one of those * on purpose: turning the storefront off removes this controller entirely * (Capability::blocksStorefront), so there is no state in which this page renders and that * row should not. * * Each row shows TWO things, because a restaurant is deciding about both: the room — a short * silent clip of the moment the system is for — and, under it, the screen their staff would * actually touch. A page of screenshots alone reads as a manual; a page of stock footage * alone says nothing about the product. The clip is the headline and the screen is the proof. * * Rows with no clip (a printed menu, an interface in Arabic) carry the screen alone rather * than borrowing footage that is about something else. * * The clip is a fixed 4:3 box that crops to fit, so every film renders at the same size. The * screen keeps its own shape and carries its real pixel size, because the shots are not all * one ratio and a single hard-coded pair would hand the browser the wrong box to reserve. */ $cap = \App\Services\Capability::class; $svcRows = [ ['', 'online', 'online', 1000, 760, true, t_raw('partner.svc_online_eyebrow')], [$cap::POS, 'pos', 'pos', 1000, 645, true, ''], [$cap::QR, 'qr', 'qr', 1000, 760, true, ''], [$cap::KIOSK, 'kiosk', 'kiosk', 1000, 625, true, ''], [$cap::KDS, 'kds', 'kds', 1000, 760, true, ''], [$cap::SCREENS, 'screens', 'screens', 1000, 760, true, ''], [$cap::PRINT_MENU, 'print_menu', 'print-menu', 1100, 779, false, ''], [$cap::RESERVATIONS, 'reservations', 'reservations', 1000, 627, true, ''], [$cap::LOYALTY, 'loyalty', 'loyalty', 1000, 760, true, ''], ['', 'languages', 'languages', 1000, 760, false, t_raw('partner.svc_languages_eyebrow')], ]; $services = []; foreach ($svcRows as [$capability, $key, $img, $w, $h, $hasFilm, $eyebrow]) { if ($capability !== '' && $cap::lacks($capability)) { continue; } // Artwork resolves through t() like the copy, so each row's screenshot, clip and poster are // chosen from the media library rather than derived from its key. A blank video simply hides the // clip — which is how the two rows that never had one (print menu, languages) now behave, with // no special case: they ship blank. $svcFilm = trim(t_raw('partner.svc_' . $key . '_video')); $svcPost = trim(t_raw('partner.svc_' . $key . '_poster')); $services[] = [ 'cap' => $capability, 'eyebrow' => $eyebrow !== '' ? $eyebrow : $cap::label($capability), 'img' => t_raw('partner.svc_' . $key . '_image'), 'film' => $svcFilm !== '' ? media($svcFilm) : '', 'poster' => $svcPost !== '' ? media($svcPost) : '', 'w' => $w, 'h' => $h, 'title' => t_raw('partner.svc_' . $key . '_title'), 'text' => t_raw('partner.svc_' . $key . '_text'), 'bullets' => [ t_raw('partner.svc_' . $key . '_b1'), t_raw('partner.svc_' . $key . '_b2'), t_raw('partner.svc_' . $key . '_b3'), ], ]; } @endphp @php // The whole top of the page — heading, buttons and the owner faces beside them. Its switch // used to cover only the faces, so the section itself could not be hidden. @endphp @if (setting('partner_hero_enabled', '1') === '1')
{{ t_raw('partner.hero_eyebrow') }}

{{ t_raw('partner.hero_title', [':site' => setting('site_name', 'QuickMunch')]) }}

{{ t_raw('partner.hero_sub') }}

@php /* Both buttons carry an editable glyph, and each shows only while it has a label — a blank label used to render an empty pill. The first button's icon was hardcoded here, so the one thing people click was the one thing the Partner page's editor could not change. */ @endphp @php $ctaGo = trim(t_raw('partner.cta_get_started')); $ctaGoIco = trim(t_raw('partner.cta_get_started_icon')); $ctaSee = trim(t_raw('partner.cta_see_pricing')); $ctaSeeIco = trim(t_raw('partner.cta_see_pricing_icon')); @endphp @if (($ctaGo !== '' && vendor_signup_open()) || $ctaSee !== '') @endif
{{ number_format($stats['restaurants']) }}+{{ t_raw('home.stats.restaurants') }}
{{ number_format($stats['orders']) }}+{{ t_raw('home.stats.orders') }}
{{ number_format($stats['cuisines']) }}{{ t_raw('partner.stat_cuisines') }}
@if ($partnerSpotlights->isNotEmpty()) @endif
@endif @php /* Pricing leads the page: the plans are the decision a prospective partner came to make, so they sit first under the fold (the operator's ask), with the why-partner story following. Section toggles in the editor mirror this order. */ @endphp @if (setting('partner_plans_enabled', '1') === '1') @php /* THE pricing section lives in partials/pricing-plans.php now, because the signup page's Change-plan popup shows the very same section — one markup, one set of figures, wherever a tier is chosen. */ @endphp @partial('pricing-plans', ['plans' => $plans, 'annualOn' => $annualOn ?? false, 'annualPct' => $annualPct ?? 0.0]) @endif @if (setting('partner_benefits_enabled', '1') === '1')
{{ t_raw('partner.benefits_eyebrow') }}

{{ t_raw('partner.benefits_title') }}

{{ t_raw('partner.benefits_sub') }}

@foreach ($benefits as [$icon, $title, $text])
{!! icon_html($icon, '') !!}

{{ $title }}

{{ $text }}

@endforeach
@endif @php /* One row per service the platform actually runs, alternating sides. Built on the same split the About page uses — Bootstrap's grid with .qm-eyebrow / .qm-section-title over it — so there is no new CSS and right-to-left comes from the logical grid rather than from a mirrored rule. The whole block goes if every service is switched off, exactly as Capability::filterNav() drops a group that loses all its children. */ @endphp @if ($services && setting('partner_services_enabled', '1') === '1')
{{ t_raw('partner.svc_eyebrow') }}

{{ t_raw('partner.svc_title') }}

{{ t_raw('partner.svc_sub') }}

@foreach ($services as $i => $s) @php $flip = $i % 2 === 1; @endphp
@php // qm-partner-copy insets the text so the screen can straddle the film's // edge without reaching it. See the rule for why the gutter itself is // left alone. @endphp
@php // One measured block, centred in its column: the copy keeps the same distance from // the media and from the page edge whichever side it sits on, instead of hugging // the outer edge on left rows and the media on flipped ones. @endphp
{{ $s['eyebrow'] }} @php // The page's heading ladder is 30px for a section, 17-18px for a card. // A service row is a sub-section of its own - its title sits one step under // the section h2 (qm-partner-title), not at card size: beside a film and a // screenshot, a 20px title read as a caption. @endphp

{{ $s['title'] }}

{{ $s['text'] }}

@php // The same ticked list the pricing tiers below already use — one bullet // style on this page, and no CSS added for a second one. @endphp
    @foreach ($s['bullets'] as $b)
  • {{ $b }}
  • @endforeach
@php /* The clip is the room and the screen lies over it, the way the landing page pairs them: the screen straddles the film's inner corner so the two read as one object rather than two panes. .qm-partner-media is the positioning context; --end marks the rows where the media sits on the left, so the screen always overhangs the edge facing the copy. Both frames are .qm-card with its padding removed — the product's own white/hairline/shadow surface, which is what a white screenshot needs on this pink page or it dissolves into it. overflow-hidden clips the media to the card radius. A row with no clip has no film to lie on, so its screen is simply the media, full width and unpositioned. */ @endphp
@if ($s['film'] !== '') @php /* Silent and looping, the same autoplay contract the sponsored cards and the hero slider already use. preload="metadata" keeps eight clips from downloading up front, and the poster is a real still of the same clip so a row is never an empty black box while it arrives. playsinline stops iOS hijacking it into a fullscreen player. */ @endphp
@endif
@php // img-fluid carries height:auto. Without it the width/height // attributes act as a presentational hint that pins a DEFINITE // height, and the shot renders stretched. @endphp {{ $s['title'] }}
@endforeach
@endif @php // Its own switch. This section shares the spotlight data with the hero faces but is a separate // part of the page, so the hero's control must not govern it. @endphp @if ($partnerSpotlights->isNotEmpty() && setting('partner_owners_enabled', '1') === '1')
{{ t_raw('partner.spotlight_eyebrow') }}

{{ t_raw('partner.spotlight_title') }}

{{ t_raw('partner.spotlight_sub', [':site' => setting('site_name', 'QuickMunch')]) }}

@php /* A rail rather than a grid: eight owners in one row of four and a stray row of four reads as a directory, while one strip that keeps going reads as a community. The product's own carousel — .qm-carousel + .qm-carousel-track, driven by the shared [data-carousel] handler in app.js, which does the drag, the scroll-snap and the end-aware arrows. qm-rail-dense sets the 256px column these portrait cards want. No new CSS and no new script. */ @endphp
@endif @if (setting('partner_steps_enabled', '1') === '1' && ($steps || $pHowEyebrow !== '' || $pHowTitle !== ''))
@if ($pHowEyebrow !== '' || $pHowTitle !== '')
@if ($pHowEyebrow !== ''){{ $pHowEyebrow }}@endif @if ($pHowTitle !== '')

{{ $pHowTitle }}

@endif
@endif
@foreach ($steps as [$num, $title, $text])
{{ $num }} @if ($title !== '')

{{ $title }}

@endif @if ($text !== '')

{{ $text }}

@endif
@endforeach
@endif @if (setting('partner_cta_enabled', '1') === '1')

{{ t_raw('partner.cta_title') }}

{{ t_raw('partner.cta_sub', [':site' => setting('site_name', 'QuickMunch')]) }}

@if (vendor_signup_open()){{ t_raw('partner.cta_btn') }}@endif
@endif @endsection