Public:
- /escape-rooms: Leaflet + OpenStreetMap map with marker clustering and a
searchable list, both built from a cached slim JSON feed
- /escape-rooms/{id}-{slug}: room detail with a mini-map and user reviews
(rating + title + body, login required)
- /escape-rooms/suggest: visitor submission form with click-to-drop-pin map
and reCAPTCHA v3; new rooms land as pending
Data:
- EscapeRoom / EscapeRoomReview entities (soft-delete), migration
- app:escaperooms:import-osm console command pulls leisure=escape_game from
the Overpass API, upserts by (osmType, osmId), skips locked rows;
--tiled / --area / --bbox options
Admin (new "Website Admin" area, separate from Game Admin):
- src/Website/Controller/AdminEscapeRoomController.php at /admin/escape-rooms:
status-filtered list, new/edit, publish/hide/reject, delete, review removal
- game admin sidebar extracted into a block and cross-linked
Assets: leaflet + leaflet.markercluster; escaperoom-map and escaperoom-detail
Encore entries.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
106 lines
4.3 KiB
Twig
106 lines
4.3 KiB
Twig
{% extends 'layout/site.html.twig' %}
|
|
|
|
{% block title %}Suggest an escape room | {{ 'site.name'|trans }}{% endblock %}
|
|
|
|
{% block stylesheets %}
|
|
{{ parent() }}
|
|
{{ encore_entry_link_tags('escaperoom-detail') }}
|
|
<style>
|
|
#escaperoom-suggest-map {
|
|
height: 340px;
|
|
width: 100%;
|
|
border-radius: 8px;
|
|
z-index: 0;
|
|
}
|
|
</style>
|
|
{% endblock %}
|
|
|
|
{% block body %}
|
|
<div class="row justify-content-center">
|
|
<div class="col-lg-8">
|
|
<nav aria-label="breadcrumb">
|
|
<ol class="breadcrumb small">
|
|
<li class="breadcrumb-item"><a href="{{ path('website_escaperooms') }}">Escape room map</a></li>
|
|
<li class="breadcrumb-item active" aria-current="page">Suggest a room</li>
|
|
</ol>
|
|
</nav>
|
|
|
|
<h1 class="h3 fw-bold mb-1">Suggest an escape room</h1>
|
|
<p class="text-secondary">Know a physical escape room that isn't on the map? Add it here — an admin will review it before it goes live.</p>
|
|
|
|
<div class="card shadow-sm">
|
|
<div class="card-body">
|
|
{{ form_errors(form) }}
|
|
{{ form_start(form) }}
|
|
<div class="mb-3">
|
|
{{ form_label(form.name) }}
|
|
{{ form_widget(form.name, {attr: {class: 'form-control'}}) }}
|
|
{{ form_errors(form.name) }}
|
|
</div>
|
|
<div class="mb-3">
|
|
{{ form_label(form.venue) }}
|
|
{{ form_widget(form.venue, {attr: {class: 'form-control'}}) }}
|
|
{{ form_errors(form.venue) }}
|
|
</div>
|
|
|
|
<div class="row g-2">
|
|
<div class="col-9 mb-3">
|
|
{{ form_label(form.street) }}
|
|
{{ form_widget(form.street, {attr: {class: 'form-control'}}) }}
|
|
</div>
|
|
<div class="col-3 mb-3">
|
|
{{ form_label(form.houseNumber) }}
|
|
{{ form_widget(form.houseNumber, {attr: {class: 'form-control'}}) }}
|
|
</div>
|
|
</div>
|
|
<div class="row g-2">
|
|
<div class="col-4 mb-3">
|
|
{{ form_label(form.postcode) }}
|
|
{{ form_widget(form.postcode, {attr: {class: 'form-control'}}) }}
|
|
</div>
|
|
<div class="col-8 mb-3">
|
|
{{ form_label(form.city) }}
|
|
{{ form_widget(form.city, {attr: {class: 'form-control'}}) }}
|
|
</div>
|
|
</div>
|
|
<div class="mb-3">
|
|
{{ form_label(form.country) }}
|
|
{{ form_widget(form.country, {attr: {class: 'form-select'}}) }}
|
|
</div>
|
|
<div class="row g-2">
|
|
<div class="col-sm-6 mb-3">
|
|
{{ form_label(form.website) }}
|
|
{{ form_widget(form.website, {attr: {class: 'form-control'}}) }}
|
|
</div>
|
|
<div class="col-sm-6 mb-3">
|
|
{{ form_label(form.phone) }}
|
|
{{ form_widget(form.phone, {attr: {class: 'form-control'}}) }}
|
|
</div>
|
|
</div>
|
|
|
|
<label class="form-label">Location <span class="text-secondary fw-normal">— click the map to drop a pin</span></label>
|
|
<div id="escaperoom-suggest-map" class="mb-2"></div>
|
|
{{ form_widget(form.latitude) }}
|
|
{{ form_widget(form.longitude) }}
|
|
{{ form_errors(form.latitude) }}
|
|
{{ form_errors(form.longitude) }}
|
|
|
|
<div class="mt-3">
|
|
{{ form_row(form.captcha) }}
|
|
</div>
|
|
|
|
<div class="d-grid mt-3">
|
|
<button type="submit" class="btn btn-primary">Submit for review</button>
|
|
</div>
|
|
{{ form_end(form) }}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endblock %}
|
|
|
|
{% block javascripts %}
|
|
{{ parent() }}
|
|
{{ encore_entry_script_tags('escaperoom-detail') }}
|
|
{% endblock %}
|