|
- <?php
- /**
- * @var \App\View\AppView $this
- * @var iterable<\App\Model\Entity\Territory> $territories
- */
- $this->assign('title', 'Territories');
-
- $territoriesData = [];
- foreach ($territories as $territory) {
- $addresses = [];
- foreach ($territory->addresses as $address) {
- $addresses[] = [
- 'id' => $address->id,
- 'full_address' => $address->full_address,
- 'lat' => (float)$address->lat,
- 'lng' => (float)$address->lng,
- ];
- }
- $territoriesData[] = [
- 'id' => $territory->id,
- 'name' => $territory->name,
- 'polygon' => $territory->polygon,
- 'addresses' => $addresses,
- ];
- }
- $territoriesJson = str_replace('</', '<\/', (string)json_encode($territoriesData));
-
- $mapVar = $this->Leaflet->name();
- ?>
- <div class="content">
- <div class="page-header">
- <h1>Territories</h1>
- <p>Use the polygon tool on the map to draw a new territory. Use the edit/delete tools to update or remove one. Use "Find addresses" to pull home addresses inside a territory from OpenStreetMap.</p>
- </div>
-
- <?= $this->Leaflet->map(['div' => ['id' => 'territories-map', 'height' => '600px']]) ?>
-
- <?php
- // Must be registered after Leaflet->map() so leaflet.js (which leaflet-draw.js extends) loads first.
- ?>
- <?= $this->Html->css('https://unpkg.com/leaflet-draw@1.0.4/dist/leaflet.draw.css', ['block' => true]) ?>
- <?= $this->Html->script('https://unpkg.com/leaflet-draw@1.0.4/dist/leaflet.draw.js', ['block' => true]) ?>
-
- <?php
- $this->Leaflet->addCustom(<<<JS
- var drawnItems = new L.FeatureGroup();
- {$mapVar}.addLayer(drawnItems);
-
- var addressIcon = L.divIcon({
- className: 'address-marker-icon',
- html: '⌂',
- iconSize: [22, 22],
- iconAnchor: [11, 11]
- });
-
- var addressLayers = {};
-
- function renderAddresses(territoryId, addresses) {
- if (addressLayers[territoryId]) {
- {$mapVar}.removeLayer(addressLayers[territoryId]);
- }
- var group = L.layerGroup();
- addresses.forEach(function (a) {
- L.marker([a.lat, a.lng], { icon: addressIcon })
- .bindPopup(a.full_address)
- .addTo(group);
- });
- group.addTo({$mapVar});
- addressLayers[territoryId] = group;
- }
-
- var territoryData = {$territoriesJson};
-
- territoryData.forEach(function (t) {
- var layer = L.geoJSON(t.polygon).getLayers()[0];
- layer.territoryId = t.id;
- layer.bindPopup(t.name);
- drawnItems.addLayer(layer);
- renderAddresses(t.id, t.addresses);
- });
-
- var drawControl = new L.Control.Draw({
- draw: {
- polygon: true,
- polyline: false,
- rectangle: false,
- circle: false,
- circlemarker: false,
- marker: false
- },
- edit: {
- featureGroup: drawnItems
- }
- });
- {$mapVar}.addControl(drawControl);
-
- var csrfToken = document.querySelector('meta[name="csrf-token"]').getAttribute('content');
-
- function territoryApiRequest(url, method, body) {
- return fetch(url, {
- method: method,
- headers: {
- 'Content-Type': 'application/json',
- 'X-CSRF-Token': csrfToken,
- 'Accept': 'application/json'
- },
- body: JSON.stringify(body)
- }).then(function (res) { return res.json(); });
- }
-
- {$mapVar}.on('draw:created', function (e) {
- var layer = e.layer;
- var name = window.prompt('Name this territory:');
- if (!name) {
- return;
- }
- territoryApiRequest('/territories/add', 'POST', {
- name: name,
- polygon: layer.toGeoJSON().geometry
- }).then(function (res) {
- if (res.success) {
- layer.territoryId = res.data.id;
- layer.bindPopup(res.data.name);
- drawnItems.addLayer(layer);
- } else {
- alert('Could not save territory.');
- }
- });
- });
-
- {$mapVar}.on('draw:edited', function (e) {
- e.layers.eachLayer(function (layer) {
- if (!layer.territoryId) {
- return;
- }
- territoryApiRequest('/territories/edit/' + layer.territoryId, 'POST', {
- polygon: layer.toGeoJSON().geometry
- }).then(function (res) {
- if (!res.success) {
- alert('Could not update territory.');
- }
- });
- });
- });
-
- {$mapVar}.on('draw:deleted', function (e) {
- e.layers.eachLayer(function (layer) {
- if (!layer.territoryId) {
- return;
- }
- territoryApiRequest('/territories/delete/' + layer.territoryId, 'POST', {}).then(function (res) {
- if (!res.success) {
- alert('Could not delete territory.');
- }
- });
- });
- });
-
- document.addEventListener('click', function (e) {
- var button = e.target.closest('.js-find-addresses');
- if (!button) {
- return;
- }
- var territoryId = button.getAttribute('data-territory-id');
- var countEl = document.querySelector('.js-address-count[data-territory-id="' + territoryId + '"]');
- button.disabled = true;
- button.textContent = 'Searching…';
- territoryApiRequest('/territories/addresses/' + territoryId, 'POST', {}).then(function (res) {
- button.disabled = false;
- button.textContent = 'Find addresses';
- if (res.success) {
- renderAddresses(territoryId, res.data.addresses.map(function (a) {
- return { full_address: a.full_address, lat: parseFloat(a.lat), lng: parseFloat(a.lng) };
- }));
- if (countEl) {
- countEl.textContent = res.data.addresses.length;
- }
- } else {
- alert('Could not find addresses: ' + JSON.stringify(res.errors));
- }
- });
- });
- JS);
- $this->Leaflet->finalize();
- ?>
-
- <div class="territory-list">
- <h2>Saved territories</h2>
- <?php if (!$territoriesData): ?>
- <p class="territory-list-empty">No territories yet — draw one on the map above.</p>
- <?php else: ?>
- <table class="territory-table">
- <thead>
- <tr>
- <th>Name</th>
- <th>Created</th>
- <th>Addresses</th>
- <th></th>
- </tr>
- </thead>
- <tbody>
- <?php foreach ($territories as $territory): ?>
- <tr>
- <td><?= h($territory->name) ?></td>
- <td><?= h($territory->created) ?></td>
- <td>
- <span class="js-address-count" data-territory-id="<?= $territory->id ?>">
- <?= count($territory->addresses) ?>
- </span>
- </td>
- <td>
- <button type="button" class="button-link js-find-addresses" data-territory-id="<?= $territory->id ?>">Find addresses</button>
- </td>
- </tr>
- <?php endforeach; ?>
- </tbody>
- </table>
- <?php endif; ?>
- </div>
- </div>
|