Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions src/Humans.Application/Interfaces/ICityPlanningService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,12 +48,15 @@ public record CampPolygonDto(
string CampSlug,
string GeoJson,
double AreaSqm,
SoundZone? SoundZone);
SoundZone? SoundZone,
double? SpaceRequirementSqm);

public record CampSeasonSummaryDto(
Guid CampSeasonId,
string CampName,
string CampSlug);
string CampSlug,
double? SpaceRequirementSqm = null,
SoundZone? SoundZone = null);

public record CampPolygonHistoryEntryDto(
Guid Id,
Expand Down
41 changes: 30 additions & 11 deletions src/Humans.Infrastructure/Services/CityPlanningService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,17 +25,19 @@ public CityPlanningService(HumansDbContext dbContext, IClock clock, IOptions<Cit

public async Task<List<CampPolygonDto>> GetCampPolygonsAsync(int year, CancellationToken cancellationToken = default)
{
return await _dbContext.CampPolygons
var polygons = await _dbContext.CampPolygons
.Include(p => p.CampSeason).ThenInclude(s => s.Camp)
.Where(p => p.CampSeason.Year == year)
.Select(p => new CampPolygonDto(
p.CampSeasonId,
p.CampSeason.Name,
p.CampSeason.Camp.Slug,
p.GeoJson,
p.AreaSqm,
p.CampSeason.SoundZone))
.ToListAsync(cancellationToken);

return polygons.Select(p => new CampPolygonDto(
p.CampSeasonId,
p.CampSeason.Name,
p.CampSeason.Camp.Slug,
p.GeoJson,
p.AreaSqm,
p.CampSeason.SoundZone,
SpaceSizeToSqm(p.CampSeason.SpaceRequirement))).ToList();
}

public async Task<SoundZone?> GetCampSeasonSoundZoneAsync(Guid campSeasonId, CancellationToken cancellationToken = default)
Expand Down Expand Up @@ -64,14 +66,31 @@ public async Task<List<CampPolygonDto>> GetCampPolygonsAsync(int year, Cancellat

public async Task<List<CampSeasonSummaryDto>> GetCampSeasonsWithoutCampPolygonAsync(int year, CancellationToken cancellationToken = default)
{
return await _dbContext.CampSeasons
var seasons = await _dbContext.CampSeasons
.Include(s => s.Camp)
.Where(s => s.Year == year
&& !_dbContext.CampPolygons.Any(p => p.CampSeasonId == s.Id))
.Select(s => new CampSeasonSummaryDto(s.Id, s.Name, s.Camp.Slug))
.ToListAsync(cancellationToken);

return seasons.Select(s => new CampSeasonSummaryDto(s.Id, s.Name, s.Camp.Slug, SpaceSizeToSqm(s.SpaceRequirement), s.SoundZone)).ToList();
}

private static double? SpaceSizeToSqm(SpaceSize? size) => size switch
{
SpaceSize.Sqm150 => 150,
SpaceSize.Sqm300 => 300,
SpaceSize.Sqm450 => 450,
SpaceSize.Sqm600 => 600,
SpaceSize.Sqm800 => 800,
SpaceSize.Sqm1000 => 1000,
SpaceSize.Sqm1200 => 1200,
SpaceSize.Sqm1500 => 1500,
SpaceSize.Sqm1800 => 1800,
SpaceSize.Sqm2200 => 2200,
SpaceSize.Sqm2800 => 2800,
_ => null
};

public async Task<List<CampPolygonHistoryEntryDto>> GetCampPolygonHistoryAsync(Guid campSeasonId, CancellationToken cancellationToken = default)
{
var rows = await _dbContext.CampPolygonHistories
Expand All @@ -82,7 +101,7 @@ public async Task<List<CampPolygonHistoryEntryDto>> GetCampPolygonHistoryAsync(G

return rows.Select(h => new CampPolygonHistoryEntryDto(
h.Id,
h.ModifiedByUser.UserName ?? h.ModifiedByUserId.ToString(),
h.ModifiedByUser.DisplayName ?? h.ModifiedByUserId.ToString(),
h.ModifiedAt.InZone(DateTimeZone.Utc).ToDateTimeUnspecified()
.ToString("d MMM yyyy HH:mm", System.Globalization.CultureInfo.InvariantCulture),
h.AreaSqm,
Expand Down
2 changes: 2 additions & 0 deletions src/Humans.Web/Resources/SharedResource.ca.resx
Original file line number Diff line number Diff line change
Expand Up @@ -1399,10 +1399,12 @@
<data name="CityPlanning_Admin_LimitZoneUploaded" xml:space="preserve"><value>Zona límit pujada</value></data>
<data name="CityPlanning_Admin_LimitZoneDeleteConfirm" xml:space="preserve"><value>Eliminar la zona límit?</value></data>
<data name="CityPlanning_Admin_LimitZoneEmpty" xml:space="preserve"><value>Encara no s'ha pujat cap zona límit.</value></data>
<data name="CityPlanning_Admin_LimitZoneHint" xml:space="preserve"><value>Les entitats poden incloure una propietat SoundZone opcional. Valors vàlids: blue, green, yellow, orange, red, o dos combinats amb un guió baix (p. ex. yellow_orange).</value></data>
<data name="CityPlanning_Admin_OfficialZonesCard" xml:space="preserve"><value>Zones oficials</value></data>
<data name="CityPlanning_Admin_OfficialZonesUploaded" xml:space="preserve"><value>Zones oficials pujades</value></data>
<data name="CityPlanning_Admin_OfficialZonesDeleteConfirm" xml:space="preserve"><value>Eliminar les zones oficials?</value></data>
<data name="CityPlanning_Admin_OfficialZonesEmpty" xml:space="preserve"><value>Encara no s'han pujat zones oficials.</value></data>
<data name="CityPlanning_Admin_OfficialZonesHint" xml:space="preserve"><value>L'etiqueta de cada entitat es llegeix de la propietat Name, si és present.</value></data>
<data name="CityPlanning_Admin_UploadGeoJson" xml:space="preserve"><value>Pujar arxiu GeoJSON</value></data>
<data name="CityPlanning_Admin_Upload" xml:space="preserve"><value>Pujar</value></data>
<data name="CityPlanning_Admin_Download" xml:space="preserve"><value>Descarregar</value></data>
Expand Down
2 changes: 2 additions & 0 deletions src/Humans.Web/Resources/SharedResource.de.resx
Original file line number Diff line number Diff line change
Expand Up @@ -1398,10 +1398,12 @@
<data name="CityPlanning_Admin_LimitZoneUploaded" xml:space="preserve"><value>Grenzzone hochgeladen</value></data>
<data name="CityPlanning_Admin_LimitZoneDeleteConfirm" xml:space="preserve"><value>Grenzzone löschen?</value></data>
<data name="CityPlanning_Admin_LimitZoneEmpty" xml:space="preserve"><value>Noch keine Grenzzone hochgeladen.</value></data>
<data name="CityPlanning_Admin_LimitZoneHint" xml:space="preserve"><value>Features können eine optionale SoundZone-Eigenschaft enthalten. Gültige Werte: blue, green, yellow, orange, red, oder zwei kombiniert mit Unterstrich (z. B. yellow_orange).</value></data>
<data name="CityPlanning_Admin_OfficialZonesCard" xml:space="preserve"><value>Offizielle Zonen</value></data>
<data name="CityPlanning_Admin_OfficialZonesUploaded" xml:space="preserve"><value>Offizielle Zonen hochgeladen</value></data>
<data name="CityPlanning_Admin_OfficialZonesDeleteConfirm" xml:space="preserve"><value>Offizielle Zonen löschen?</value></data>
<data name="CityPlanning_Admin_OfficialZonesEmpty" xml:space="preserve"><value>Noch keine offiziellen Zonen hochgeladen.</value></data>
<data name="CityPlanning_Admin_OfficialZonesHint" xml:space="preserve"><value>Das Label jedes Features wird aus der Eigenschaft Name gelesen, falls vorhanden.</value></data>
<data name="CityPlanning_Admin_UploadGeoJson" xml:space="preserve"><value>GeoJSON-Datei hochladen</value></data>
<data name="CityPlanning_Admin_Upload" xml:space="preserve"><value>Hochladen</value></data>
<data name="CityPlanning_Admin_Download" xml:space="preserve"><value>Herunterladen</value></data>
Expand Down
2 changes: 2 additions & 0 deletions src/Humans.Web/Resources/SharedResource.es.resx
Original file line number Diff line number Diff line change
Expand Up @@ -1400,10 +1400,12 @@
<data name="CityPlanning_Admin_LimitZoneUploaded" xml:space="preserve"><value>Zona límite subida</value></data>
<data name="CityPlanning_Admin_LimitZoneDeleteConfirm" xml:space="preserve"><value>¿Eliminar la zona límite?</value></data>
<data name="CityPlanning_Admin_LimitZoneEmpty" xml:space="preserve"><value>Aún no se ha subido ninguna zona límite.</value></data>
<data name="CityPlanning_Admin_LimitZoneHint" xml:space="preserve"><value>Las entidades pueden incluir una propiedad SoundZone opcional. Valores válidos: blue, green, yellow, orange, red, o dos combinados con guión bajo (p. ej. yellow_orange).</value></data>
<data name="CityPlanning_Admin_OfficialZonesCard" xml:space="preserve"><value>Zonas Oficiales</value></data>
<data name="CityPlanning_Admin_OfficialZonesUploaded" xml:space="preserve"><value>Zonas oficiales subidas</value></data>
<data name="CityPlanning_Admin_OfficialZonesDeleteConfirm" xml:space="preserve"><value>¿Eliminar las zonas oficiales?</value></data>
<data name="CityPlanning_Admin_OfficialZonesEmpty" xml:space="preserve"><value>Aún no se han subido zonas oficiales.</value></data>
<data name="CityPlanning_Admin_OfficialZonesHint" xml:space="preserve"><value>La etiqueta de cada entidad se lee de la propiedad Name, si está presente.</value></data>
<data name="CityPlanning_Admin_UploadGeoJson" xml:space="preserve"><value>Subir archivo GeoJSON</value></data>
<data name="CityPlanning_Admin_Upload" xml:space="preserve"><value>Subir</value></data>
<data name="CityPlanning_Admin_Download" xml:space="preserve"><value>Descargar</value></data>
Expand Down
2 changes: 2 additions & 0 deletions src/Humans.Web/Resources/SharedResource.fr.resx
Original file line number Diff line number Diff line change
Expand Up @@ -1398,10 +1398,12 @@
<data name="CityPlanning_Admin_LimitZoneUploaded" xml:space="preserve"><value>Zone limite importée</value></data>
<data name="CityPlanning_Admin_LimitZoneDeleteConfirm" xml:space="preserve"><value>Supprimer la zone limite ?</value></data>
<data name="CityPlanning_Admin_LimitZoneEmpty" xml:space="preserve"><value>Aucune zone limite importée.</value></data>
<data name="CityPlanning_Admin_LimitZoneHint" xml:space="preserve"><value>Les entités peuvent inclure une propriété SoundZone optionnelle. Valeurs valides : blue, green, yellow, orange, red, ou deux combinées avec un tiret bas (ex. yellow_orange).</value></data>
<data name="CityPlanning_Admin_OfficialZonesCard" xml:space="preserve"><value>Zones officielles</value></data>
<data name="CityPlanning_Admin_OfficialZonesUploaded" xml:space="preserve"><value>Zones officielles importées</value></data>
<data name="CityPlanning_Admin_OfficialZonesDeleteConfirm" xml:space="preserve"><value>Supprimer les zones officielles ?</value></data>
<data name="CityPlanning_Admin_OfficialZonesEmpty" xml:space="preserve"><value>Aucune zone officielle importée.</value></data>
<data name="CityPlanning_Admin_OfficialZonesHint" xml:space="preserve"><value>Le libellé de chaque entité est lu depuis la propriété Name, si elle est présente.</value></data>
<data name="CityPlanning_Admin_UploadGeoJson" xml:space="preserve"><value>Importer un fichier GeoJSON</value></data>
<data name="CityPlanning_Admin_Upload" xml:space="preserve"><value>Importer</value></data>
<data name="CityPlanning_Admin_Download" xml:space="preserve"><value>Télécharger</value></data>
Expand Down
2 changes: 2 additions & 0 deletions src/Humans.Web/Resources/SharedResource.it.resx
Original file line number Diff line number Diff line change
Expand Up @@ -1398,10 +1398,12 @@
<data name="CityPlanning_Admin_LimitZoneUploaded" xml:space="preserve"><value>Zona limite caricata</value></data>
<data name="CityPlanning_Admin_LimitZoneDeleteConfirm" xml:space="preserve"><value>Eliminare la zona limite?</value></data>
<data name="CityPlanning_Admin_LimitZoneEmpty" xml:space="preserve"><value>Nessuna zona limite ancora caricata.</value></data>
<data name="CityPlanning_Admin_LimitZoneHint" xml:space="preserve"><value>Le feature possono includere una proprietà SoundZone opzionale. Valori validi: blue, green, yellow, orange, red, o due combinati con un underscore (es. yellow_orange).</value></data>
<data name="CityPlanning_Admin_OfficialZonesCard" xml:space="preserve"><value>Zone ufficiali</value></data>
<data name="CityPlanning_Admin_OfficialZonesUploaded" xml:space="preserve"><value>Zone ufficiali caricate</value></data>
<data name="CityPlanning_Admin_OfficialZonesDeleteConfirm" xml:space="preserve"><value>Eliminare le zone ufficiali?</value></data>
<data name="CityPlanning_Admin_OfficialZonesEmpty" xml:space="preserve"><value>Nessuna zona ufficiale ancora caricata.</value></data>
<data name="CityPlanning_Admin_OfficialZonesHint" xml:space="preserve"><value>L'etichetta di ogni feature viene letta dalla proprietà Name, se presente.</value></data>
<data name="CityPlanning_Admin_UploadGeoJson" xml:space="preserve"><value>Carica file GeoJSON</value></data>
<data name="CityPlanning_Admin_Upload" xml:space="preserve"><value>Carica</value></data>
<data name="CityPlanning_Admin_Download" xml:space="preserve"><value>Scarica</value></data>
Expand Down
2 changes: 2 additions & 0 deletions src/Humans.Web/Resources/SharedResource.resx
Original file line number Diff line number Diff line change
Expand Up @@ -1416,10 +1416,12 @@
<data name="CityPlanning_Admin_LimitZoneUploaded" xml:space="preserve"><value>Limit zone uploaded</value></data>
<data name="CityPlanning_Admin_LimitZoneDeleteConfirm" xml:space="preserve"><value>Delete the limit zone?</value></data>
<data name="CityPlanning_Admin_LimitZoneEmpty" xml:space="preserve"><value>No limit zone uploaded yet.</value></data>
<data name="CityPlanning_Admin_LimitZoneHint" xml:space="preserve"><value>Features may include an optional SoundZone property. Valid values: blue, green, yellow, orange, red, or two combined with an underscore (e.g. yellow_orange).</value></data>
<data name="CityPlanning_Admin_OfficialZonesCard" xml:space="preserve"><value>Official Zones</value></data>
<data name="CityPlanning_Admin_OfficialZonesUploaded" xml:space="preserve"><value>Official zones uploaded</value></data>
<data name="CityPlanning_Admin_OfficialZonesDeleteConfirm" xml:space="preserve"><value>Delete the official zones?</value></data>
<data name="CityPlanning_Admin_OfficialZonesEmpty" xml:space="preserve"><value>No official zones uploaded yet.</value></data>
<data name="CityPlanning_Admin_OfficialZonesHint" xml:space="preserve"><value>Each feature's label is read from the Name property, if present.</value></data>
<data name="CityPlanning_Admin_UploadGeoJson" xml:space="preserve"><value>Upload GeoJSON file</value></data>
<data name="CityPlanning_Admin_Upload" xml:space="preserve"><value>Upload</value></data>
<data name="CityPlanning_Admin_Download" xml:space="preserve"><value>Download</value></data>
Expand Down
2 changes: 2 additions & 0 deletions src/Humans.Web/Views/CityPlanning/Admin.cshtml
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@
<div class="mb-2">
<label class="form-label small fw-semibold">@Localizer["CityPlanning_Admin_UploadGeoJson"]</label>
<input type="file" name="file" accept=".geojson,.json" class="form-control form-control-sm" required />
<div class="form-text">@Localizer["CityPlanning_Admin_LimitZoneHint"]</div>
</div>
<button type="submit" class="btn btn-primary btn-sm">
<i class="fa fa-upload me-1"></i> @Localizer["CityPlanning_Admin_Upload"]
Expand Down Expand Up @@ -161,6 +162,7 @@
<div class="mb-2">
<label class="form-label small fw-semibold">@Localizer["CityPlanning_Admin_UploadGeoJson"]</label>
<input type="file" name="file" accept=".geojson,.json" class="form-control form-control-sm" required />
<div class="form-text">@Localizer["CityPlanning_Admin_OfficialZonesHint"]</div>
</div>
<button type="submit" class="btn btn-primary btn-sm">
<i class="fa fa-upload me-1"></i> @Localizer["CityPlanning_Admin_Upload"]
Expand Down
29 changes: 16 additions & 13 deletions src/Humans.Web/Views/CityPlanning/Index.cshtml
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,22 @@
</div>
}

<!-- Admin panel link -->
@if (isMapAdmin)
{
<div class="position-absolute top-0 end-0 m-3">
<div class="card shadow-sm">
<div class="card-body d-flex flex-column align-items-center gap-2">
<div class="d-flex align-items-center gap-2">
<a href="/CityPlanning/Admin" class="btn btn-outline-primary btn-sm shadow-sm">
<i class="fa fa-cog me-1"></i> @Localizer["CityPlanning_AdminLink"]
</a>
</div>
</div>
</div>
</div>
}

<!-- Toolbars -->
<div class="position-absolute bottom-0 start-50 translate-middle-x mb-3 d-flex flex-row gap-2">
@if (isPlacementOpen || isMapAdmin)
Expand Down Expand Up @@ -95,19 +111,6 @@
<button id="cancel-btn" class="btn btn-outline-secondary btn-sm" style="display:none">
<i class="fa fa-times me-1"></i> @Localizer["Common_Cancel"]
</button>
<button id="history-btn" class="btn btn-outline-primary btn-sm" style="display:none" disabled>
<i class="fa fa-history me-1"></i> @Localizer["CityPlanning_HistoryButton"]
</button>
</div>
</div>
}
@if (isMapAdmin)
{
<div class="card">
<div class="card-body">
<a href="/CityPlanning/Admin" class="btn btn-outline-primary btn-sm">
<i class="fa fa-cog me-1"></i> @Localizer["CityPlanning_AdminLink"]
</a>
</div>
</div>
}
Expand Down
2 changes: 1 addition & 1 deletion src/Humans.Web/Views/CityPlanning/_HistoryOffcanvas.cshtml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<div class="offcanvas offcanvas-end" tabindex="-1" id="history-panel" style="width:360px;">
<div class="offcanvas-header">
<h5 class="offcanvas-title">@Localizer["CityPlanning_HistoryTitle"]</h5>
<h5 class="offcanvas-title" id="history-panel-title">@Localizer["CityPlanning_HistoryTitle"]</h5>
<button type="button" class="btn-close" data-bs-dismiss="offcanvas"></button>
</div>
<div class="offcanvas-body p-2" id="history-list">
Expand Down
Loading
Loading