diff --git a/symfony/fixtures/actors.yaml b/symfony/fixtures/actors.yaml index 48383ca1..4205697f 100755 --- a/symfony/fixtures/actors.yaml +++ b/symfony/fixtures/actors.yaml @@ -10,6 +10,7 @@ App\Entity\Actor: administrativeScopes: 'x @administrative_scope_*' officeName: officeAddress: + geoData: '@geoData_' officeLocation: '., .' contactName: contactPosition: diff --git a/symfony/fixtures/resources.yaml b/symfony/fixtures/resources.yaml index c877a777..281f38c4 100644 --- a/symfony/fixtures/resources.yaml +++ b/symfony/fixtures/resources.yaml @@ -8,6 +8,7 @@ App\Entity\Resource: endAt: '' thematics: 'x @thematic_*' link: https:// + geoData: '@geoData_' createdBy: '@user_*' isValidated: - author: \ No newline at end of file + author: diff --git a/symfony/migrations/Version20241213222822.php b/symfony/migrations/Version20241213222822.php new file mode 100644 index 00000000..7368358c --- /dev/null +++ b/symfony/migrations/Version20241213222822.php @@ -0,0 +1,36 @@ +addSql('ALTER TABLE actor ADD geo_data_id INT DEFAULT NULL'); + $this->addSql('ALTER TABLE actor ADD CONSTRAINT FK_447556F980E32C3E FOREIGN KEY (geo_data_id) REFERENCES geo_data (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('CREATE UNIQUE INDEX UNIQ_447556F980E32C3E ON actor (geo_data_id)'); + } + + public function down(Schema $schema): void + { + // this down() migration is auto-generated, please modify it to your needs + $this->addSql('CREATE SCHEMA public'); + $this->addSql('ALTER TABLE actor DROP CONSTRAINT FK_447556F980E32C3E'); + $this->addSql('DROP INDEX UNIQ_447556F980E32C3E'); + $this->addSql('ALTER TABLE actor DROP geo_data_id'); + } +} diff --git a/symfony/migrations/Version20241213223524.php b/symfony/migrations/Version20241213223524.php new file mode 100644 index 00000000..0835b180 --- /dev/null +++ b/symfony/migrations/Version20241213223524.php @@ -0,0 +1,32 @@ +addSql('ALTER TABLE geo_data ALTER osm_id TYPE INT'); + } + + public function down(Schema $schema): void + { + // this down() migration is auto-generated, please modify it to your needs + $this->addSql('CREATE SCHEMA public'); + $this->addSql('ALTER TABLE geo_data ALTER osm_id TYPE BIGINT'); + } +} diff --git a/symfony/migrations/Version20241213223750.php b/symfony/migrations/Version20241213223750.php new file mode 100644 index 00000000..9aff5538 --- /dev/null +++ b/symfony/migrations/Version20241213223750.php @@ -0,0 +1,32 @@ +addSql('ALTER TABLE geo_data ALTER osm_id TYPE BIGINT'); + } + + public function down(Schema $schema): void + { + // this down() migration is auto-generated, please modify it to your needs + $this->addSql('CREATE SCHEMA public'); + $this->addSql('ALTER TABLE geo_data ALTER osm_id TYPE INT'); + } +} diff --git a/symfony/src/Entity/Actor.php b/symfony/src/Entity/Actor.php index 517af75f..3b15ff96 100755 --- a/symfony/src/Entity/Actor.php +++ b/symfony/src/Entity/Actor.php @@ -11,6 +11,7 @@ use ApiPlatform\Metadata\Post; use ApiPlatform\Metadata\Put; use App\Entity\Trait\BlameableEntity; +use App\Entity\Trait\LocalizableEntity; use App\Entity\Trait\SluggableEntity; use App\Entity\Trait\TimestampableEntity; use App\Entity\Trait\ValidateableEntity; @@ -67,12 +68,13 @@ class Actor { use TimestampableEntity; use SluggableEntity; + use LocalizableEntity; use BlameableEntity; use ValidateableEntity; public const ACTOR_READ_COLLECTION = 'actor:read_collection'; public const ACTOR_READ_COLLECTION_ALL = 'actor:read_collection:all'; public const ACTOR_READ_ITEM = 'actor:read_item'; - private const ACTOR_WRITE = 'actor:write'; + public const ACTOR_WRITE = 'actor:write'; #[ORM\Id] #[ORM\Column(type: 'uuid', unique: true)] diff --git a/symfony/src/Entity/GeoData.php b/symfony/src/Entity/GeoData.php index 65db4af1..a2d7a35a 100755 --- a/symfony/src/Entity/GeoData.php +++ b/symfony/src/Entity/GeoData.php @@ -15,15 +15,15 @@ class GeoData private ?int $id = null; #[ORM\Column(type: 'bigint')] - #[Groups([Project::GET_FULL, Resource::GET_FULL])] + #[Groups([Project::GET_FULL, Resource::GET_FULL, Actor::ACTOR_READ_ITEM])] private ?int $osmId = null; #[ORM\Column] - #[Groups([Project::GET_FULL, Resource::GET_FULL])] + #[Groups([Project::GET_FULL, Resource::GET_FULL, Actor::ACTOR_READ_ITEM])] private ?string $osmType = 'node'; #[ORM\Column(length: 255)] - #[Groups([PROJECT::GET_FULL, PROJECT::GET_PARTIAL, Actor::ACTOR_READ_ITEM, Resource::GET_FULL, Resource::WRITE])] + #[Groups([PROJECT::GET_FULL, PROJECT::GET_PARTIAL, Resource::GET_FULL, Resource::WRITE, Actor::ACTOR_READ_COLLECTION])] private ?string $name = null; #[ORM\Column(nullable: true)] @@ -115,7 +115,7 @@ public function setAddress(?array $address): static return $this; } - #[Groups([Project::GET_PARTIAL])] + #[Groups([Project::GET_PARTIAL, Resource::GET_FULL, Actor::ACTOR_READ_COLLECTION])] public function getCoords(): ?array { return [ diff --git a/symfony/src/Entity/Thematic.php b/symfony/src/Entity/Thematic.php index d63eb367..e869088e 100755 --- a/symfony/src/Entity/Thematic.php +++ b/symfony/src/Entity/Thematic.php @@ -35,7 +35,7 @@ class Thematic #[ORM\Id] #[ORM\GeneratedValue] #[ORM\Column] - #[Groups([self::THEMATIC_READ, Resource::GET_FULL, Project::GET_FULL, Project::GET_PARTIAL])] + #[Groups([self::THEMATIC_READ, Resource::GET_FULL, Actor::ACTOR_READ_COLLECTION, Project::GET_FULL, Project::GET_PARTIAL])] private ?int $id = null; #[ORM\Column(length: 255)] diff --git a/symfony/src/Entity/Trait/LocalizableEntity.php b/symfony/src/Entity/Trait/LocalizableEntity.php index 45014acd..bd234b37 100755 --- a/symfony/src/Entity/Trait/LocalizableEntity.php +++ b/symfony/src/Entity/Trait/LocalizableEntity.php @@ -11,11 +11,11 @@ trait LocalizableEntity { - #[Groups([Project::WRITE, Resource::WRITE])] + #[Groups([Project::WRITE, Resource::WRITE, Actor::ACTOR_WRITE])] private ?array $osmData = null; #[ORM\OneToOne(cascade: ['persist', 'remove'])] - #[Groups([Project::GET_FULL, Project::GET_PARTIAL, Actor::ACTOR_READ_ITEM, Resource::GET_FULL])] + #[Groups([Project::GET_FULL, Project::GET_PARTIAL, Actor::ACTOR_READ_ITEM, Actor::ACTOR_READ_COLLECTION, Resource::GET_FULL])] private ?GeoData $geoData = null; public function getOsmData(): ?array diff --git a/vue/.env b/vue/.env new file mode 100644 index 00000000..465e365a --- /dev/null +++ b/vue/.env @@ -0,0 +1 @@ +VITE_MAPTILER_API_KEY=0tupl15DKhXOvwp27x8c \ No newline at end of file diff --git a/vue/public/img/map/actor_icon.png b/vue/public/img/map/actor_icon.png new file mode 100644 index 00000000..e192f703 Binary files /dev/null and b/vue/public/img/map/actor_icon.png differ diff --git a/vue/public/img/map/project_icon.png b/vue/public/img/map/project_icon.png new file mode 100644 index 00000000..7d9f4d3f Binary files /dev/null and b/vue/public/img/map/project_icon.png differ diff --git a/vue/public/img/map/project_icon_hover.png b/vue/public/img/map/project_icon_hover.png new file mode 100644 index 00000000..f72a7a74 Binary files /dev/null and b/vue/public/img/map/project_icon_hover.png differ diff --git a/vue/public/img/map/resource_icon.png b/vue/public/img/map/resource_icon.png new file mode 100644 index 00000000..8345de27 Binary files /dev/null and b/vue/public/img/map/resource_icon.png differ diff --git a/vue/src/App.vue b/vue/src/App.vue index 366669cd..37becc98 100644 --- a/vue/src/App.vue +++ b/vue/src/App.vue @@ -1,25 +1,26 @@ diff --git a/vue/src/assets/images/icons/map/actor_icon.png b/vue/src/assets/images/icons/map/actor_icon.png new file mode 100644 index 00000000..998d5540 Binary files /dev/null and b/vue/src/assets/images/icons/map/actor_icon.png differ diff --git a/vue/src/assets/images/icons/map/resource_icon.png b/vue/src/assets/images/icons/map/resource_icon.png new file mode 100644 index 00000000..7ec30049 Binary files /dev/null and b/vue/src/assets/images/icons/map/resource_icon.png differ diff --git a/vue/src/assets/images/map/basemap/openstreetmap.jpg b/vue/src/assets/images/map/basemap/openstreetmap.jpg new file mode 100644 index 00000000..42781707 Binary files /dev/null and b/vue/src/assets/images/map/basemap/openstreetmap.jpg differ diff --git a/vue/src/assets/images/map/basemap/satellite.jpg b/vue/src/assets/images/map/basemap/satellite.jpg new file mode 100644 index 00000000..8221358b Binary files /dev/null and b/vue/src/assets/images/map/basemap/satellite.jpg differ diff --git a/vue/src/assets/styles/global/vars/_dimensions.scss b/vue/src/assets/styles/global/vars/_dimensions.scss index 63f20a6f..8f375796 100644 --- a/vue/src/assets/styles/global/vars/_dimensions.scss +++ b/vue/src/assets/styles/global/vars/_dimensions.scss @@ -5,7 +5,7 @@ $header-mobile-height: 64px; $dim-container-w: 70rem; $dim-dialog-w: 31.25rem; -$dim-radius: 5px; +$dim-radius: 3px; // Breakpoints $bp-sm: 576px; diff --git a/vue/src/assets/styles/global/vuetifyOverrides.scss b/vue/src/assets/styles/global/vuetifyOverrides.scss index d76f685e..d3e6f7ba 100644 --- a/vue/src/assets/styles/global/vuetifyOverrides.scss +++ b/vue/src/assets/styles/global/vuetifyOverrides.scss @@ -1,3 +1,13 @@ +:root { + --v-shadow-key-umbra-opacity: rgba(0, 0, 0, 0.1); + --v-shadow-key-penumbra-opacity: rgba(0, 0, 0, 0.075); + --v-shadow-key-ambient-opacity: rgba(0, 0, 0, 0.05); +} + +.elevation-1 { + box-shadow: 0 0.125rem 0.25rem -0.125rem rgba(0, 0, 0, 0.15) !important; +} + // To be replaced by customized variables: https://vuetifyjs.com/en/features/sass-variables/#component-specific-variables .v-field--variant-solo, .v-field--variant-solo-filled { box-shadow: none !important; diff --git a/vue/src/assets/translations/fr/common.json b/vue/src/assets/translations/fr/common.json index d7dfe408..c1392a88 100644 --- a/vue/src/assets/translations/fr/common.json +++ b/vue/src/assets/translations/fr/common.json @@ -55,6 +55,7 @@ "cancel": "Annuler", "create": "Créer", "delete": "Supprimer", + "or": "OU", "errorMessages": { "required": "Ce champs est requis", "minlength": "Ce champs doit avoir au moins {min} caractères", diff --git a/vue/src/assets/translations/fr/myMap.json b/vue/src/assets/translations/fr/myMap.json new file mode 100644 index 00000000..90b79c46 --- /dev/null +++ b/vue/src/assets/translations/fr/myMap.json @@ -0,0 +1,37 @@ +{ + "myMap": { + "header": { + "share": "Partager", + "search": { + "placeholder": "Rechercher un lieu ou une donnée" + } + }, + "components": { + "opacity": "Transparence" + }, + "leftSidebar": { + "welcome": { + "title": "Bienvenue", + "description": "Composez votre carte grâce aux données mises à disposition sur la Plateforme Urbaine du Cameroun.", + "moreAccess": "Vous souhaitez avoir accès à plus de données et d’outils ?", + "close": "Fermer" + } + + }, + "rightSidebar": { + "actions": { + "about": "À propos", + "share": "Partager", + "downloadLayer": "Télécharger la couche", + "opacity": "Ajuster la transparence" + }, + "layers": { + "itemType": { + "project": "Projets", + "actor": "Acteurs", + "resource": "Ressources" + } + } + } + } +} \ No newline at end of file diff --git a/vue/src/assets/translations/fr/resources.json b/vue/src/assets/translations/fr/resources.json index 7ee0f54a..17f13bb7 100644 --- a/vue/src/assets/translations/fr/resources.json +++ b/vue/src/assets/translations/fr/resources.json @@ -35,7 +35,6 @@ "edit": "Modifier une ressource", "validate": "Valider une ressource" }, - "or": "OU", "fields": { "name": { "label": "Nom de la ressource", diff --git a/vue/src/components/forms/Geocoding.vue b/vue/src/components/forms/Geocoding.vue index 9e6bee22..dceffa05 100644 --- a/vue/src/components/forms/Geocoding.vue +++ b/vue/src/components/forms/Geocoding.vue @@ -4,17 +4,18 @@ density="compact" featureType="city" variant="outlined" - :placeholder="$t('geocoding.placeholder')" + :placeholder="placeholder" :no-data-text="$t('geocoding.noData')" :items="geocodingItems" :clearable="true" :item-value="(val) => val" :item-title="(val) => val.osmName" + v-model="osmData" @update:search="(e) => (searchQuery = e)" @click:clear="(e) => (searchQuery = '')" > @@ -34,12 +38,14 @@ import ProjectFilterModal from '@/views/projects/components/ProjectFilterModal.v import { type ResolvedImageSpecification } from 'maplibre-gl' import ShowProjectFiltersModalControl from '@/views/projects/components/map-controls/ShowProjectFiltersModalControl.vue' import router from '@/router' +import ToggleSidebarControl from '@/components/map/controls/ToggleSidebarControl.vue' type MapType = InstanceType type ProjectCard = InstanceType const projectStore = useProjectStore() const projectMap = useTemplateRef('project-map') +const toggleSidebarControl = useTemplateRef('toggle-sidebar-control') const activeProjectCard = useTemplateRef('active-project-card') const showProjectFiltersModalControl = useTemplateRef('show-project-filters-modal-control') const geojson = computed(() => MapService.getGeojson(projectStore.filteredProjects)) @@ -106,6 +112,7 @@ const showPopupOnInit = () => { onMounted(() => { if (map.value != null) { map.value.addControl(new IControl(showProjectFiltersModalControl), 'top-right') + map.value.addControl(new IControl(toggleSidebarControl), 'top-left') map.value.on('load', async () => { await setProjectLayer() showPopupOnInit() diff --git a/vue/src/views/resources/components/ResourceForm.vue b/vue/src/views/resources/components/ResourceForm.vue index 6d3b51bd..e1fd2002 100644 --- a/vue/src/views/resources/components/ResourceForm.vue +++ b/vue/src/views/resources/components/ResourceForm.vue @@ -98,9 +98,7 @@ @blur="form.link.handleChange" /> - {{ - $t('resources.form.or') - }} + {{ $t('forms.or') }}