ajout page calendrier
This commit is contained in:
parent
8aa4e107ac
commit
20a8445a5f
14 changed files with 617 additions and 5 deletions
|
@ -30,6 +30,7 @@
|
|||
}
|
||||
],
|
||||
"styles": [
|
||||
"node_modules/angular-calendar/css/angular-calendar.css",
|
||||
"src/styles.scss"
|
||||
]
|
||||
},
|
||||
|
@ -88,6 +89,7 @@
|
|||
}
|
||||
],
|
||||
"styles": [
|
||||
"node_modules/angular-calendar/css/angular-calendar.css",
|
||||
"src/styles.scss"
|
||||
]
|
||||
}
|
||||
|
|
118
frontend/package-lock.json
generated
118
frontend/package-lock.json
generated
|
@ -14,6 +14,11 @@
|
|||
"@angular/forms": "^20.3.0",
|
||||
"@angular/platform-browser": "^20.3.0",
|
||||
"@angular/router": "^20.3.0",
|
||||
"angular-calendar": "^0.32.0",
|
||||
"angular-draggable-droppable": "^9.0.1",
|
||||
"angular-resizable-element": "^8.0.0",
|
||||
"date-fns": "^4.1.0",
|
||||
"moment": "^2.0.0",
|
||||
"rxjs": "~7.8.0",
|
||||
"tslib": "^2.3.0",
|
||||
"zone.js": "~0.15.0"
|
||||
|
@ -1952,6 +1957,12 @@
|
|||
"win32"
|
||||
]
|
||||
},
|
||||
"node_modules/@mattlewis92/dom-autoscroller": {
|
||||
"version": "2.4.2",
|
||||
"resolved": "https://registry.npmjs.org/@mattlewis92/dom-autoscroller/-/dom-autoscroller-2.4.2.tgz",
|
||||
"integrity": "sha512-YbrUWREPGEjE/FU6foXcAT1YbVwqD/jkYnY1dFb0o4AxtP3s4xKBthlELjndZih8uwsDWgQZx1eNskRNe2BgZQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@modelcontextprotocol/sdk": {
|
||||
"version": "1.17.3",
|
||||
"resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.17.3.tgz",
|
||||
|
@ -3354,6 +3365,13 @@
|
|||
"win32"
|
||||
]
|
||||
},
|
||||
"node_modules/@scarf/scarf": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@scarf/scarf/-/scarf-1.4.0.tgz",
|
||||
"integrity": "sha512-xxeapPiUXdZAE3che6f3xogoJPeZgig6omHEy1rIY5WVsB3H2BHNnZH+gHG6x91SCWyQCzWGsuL2Hh3ClO5/qQ==",
|
||||
"hasInstallScript": true,
|
||||
"license": "Apache-2.0"
|
||||
},
|
||||
"node_modules/@schematics/angular": {
|
||||
"version": "20.3.4",
|
||||
"resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-20.3.4.tgz",
|
||||
|
@ -3657,6 +3675,60 @@
|
|||
"node": ">= 14.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/angular-calendar": {
|
||||
"version": "0.32.0",
|
||||
"resolved": "https://registry.npmjs.org/angular-calendar/-/angular-calendar-0.32.0.tgz",
|
||||
"integrity": "sha512-+iQ4j04SCxFv75bp8psx0Q9S7eefREE2IbwbeaSA3uqJcl7Rm1uo7mBwF9Pcg9gu6+U1NDVYlWzDsBpL9b4u3w==",
|
||||
"dependencies": {
|
||||
"@scarf/scarf": "^1.1.1",
|
||||
"calendar-utils": "^0.12.3",
|
||||
"positioning": "^3.0.0",
|
||||
"tslib": "^2.4.1"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/mattlewis92"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@angular/core": ">=20.2.0",
|
||||
"angular-draggable-droppable": "^9.0.1",
|
||||
"angular-resizable-element": "^8.0.0",
|
||||
"date-fns": "^4.0.0",
|
||||
"moment": "^2.0.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"date-fns": {
|
||||
"optional": true
|
||||
},
|
||||
"moment": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/angular-draggable-droppable": {
|
||||
"version": "9.0.1",
|
||||
"resolved": "https://registry.npmjs.org/angular-draggable-droppable/-/angular-draggable-droppable-9.0.1.tgz",
|
||||
"integrity": "sha512-nxxFzBMEzB6RsRUqnHWelt9G7QXG2wc18czYL75YhJ9IkBJOBkxXBd0ZOTeDgV9C3mmkkw+PMLJOayx0GH6gXA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@mattlewis92/dom-autoscroller": "^2.4.2",
|
||||
"tslib": "^2.4.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@angular/core": ">=20.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/angular-resizable-element": {
|
||||
"version": "8.0.0",
|
||||
"resolved": "https://registry.npmjs.org/angular-resizable-element/-/angular-resizable-element-8.0.0.tgz",
|
||||
"integrity": "sha512-cHCfz4y/G8GiKS4WHDeRPv5NPZA4BnsnEgn+z/l7wGhAQv28g7fFRRVyWQu4ZFM5YGu/d7Irv1kUGZ02pCHVdQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"tslib": "^2.3.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@angular/core": ">=20.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/ansi-escapes": {
|
||||
"version": "7.1.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-7.1.1.tgz",
|
||||
|
@ -4017,6 +4089,28 @@
|
|||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/calendar-utils": {
|
||||
"version": "0.12.4",
|
||||
"resolved": "https://registry.npmjs.org/calendar-utils/-/calendar-utils-0.12.4.tgz",
|
||||
"integrity": "sha512-OYhqJdeDRRVUdMYJMUrXtR7Go+80oEcA6VK4T3zjcUloQqcOVQKs/kp7j8Yw0HiLOcGwzF50WhLmzZoUNfkM7A==",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"date-fns": "^4.0.0",
|
||||
"luxon": "^3.0.0",
|
||||
"moment": "^2.0.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"date-fns": {
|
||||
"optional": true
|
||||
},
|
||||
"luxon": {
|
||||
"optional": true
|
||||
},
|
||||
"moment": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/call-bind-apply-helpers": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
|
||||
|
@ -4439,6 +4533,15 @@
|
|||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/date-fns": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/date-fns/-/date-fns-4.1.0.tgz",
|
||||
"integrity": "sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/kossnocorp"
|
||||
}
|
||||
},
|
||||
"node_modules/date-format": {
|
||||
"version": "4.0.14",
|
||||
"resolved": "https://registry.npmjs.org/date-format/-/date-format-4.0.14.tgz",
|
||||
|
@ -7009,6 +7112,15 @@
|
|||
"mkdirp": "bin/cmd.js"
|
||||
}
|
||||
},
|
||||
"node_modules/moment": {
|
||||
"version": "2.30.1",
|
||||
"resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz",
|
||||
"integrity": "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/mrmime": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.1.tgz",
|
||||
|
@ -7795,6 +7907,12 @@
|
|||
"node": ">=16.20.0"
|
||||
}
|
||||
},
|
||||
"node_modules/positioning": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/positioning/-/positioning-3.0.1.tgz",
|
||||
"integrity": "sha512-cqg00fwFtEu14YwlLUuvFih5ztTd9RYUguJA55lWjeIGFQTpik7ca+TMU87YhAgwWjyjcGIG6l80eUh7X6uHog==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/postcss": {
|
||||
"version": "8.5.6",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz",
|
||||
|
|
|
@ -28,6 +28,11 @@
|
|||
"@angular/forms": "^20.3.0",
|
||||
"@angular/platform-browser": "^20.3.0",
|
||||
"@angular/router": "^20.3.0",
|
||||
"angular-calendar": "^0.32.0",
|
||||
"angular-draggable-droppable": "^9.0.1",
|
||||
"angular-resizable-element": "^8.0.0",
|
||||
"date-fns": "^4.1.0",
|
||||
"moment": "^2.0.0",
|
||||
"rxjs": "~7.8.0",
|
||||
"tslib": "^2.3.0",
|
||||
"zone.js": "~0.15.0"
|
||||
|
@ -45,4 +50,4 @@
|
|||
"karma-jasmine-html-reporter": "~2.1.0",
|
||||
"typescript": "~5.9.2"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,14 @@
|
|||
import { Routes } from '@angular/router';
|
||||
import {Home} from './pages/home/home';
|
||||
import { Agenda } from './pages/agenda/agenda';
|
||||
|
||||
export const routes: Routes = [
|
||||
{
|
||||
path : '',
|
||||
component: Home
|
||||
},
|
||||
{
|
||||
path : 'agenda',
|
||||
component: Agenda
|
||||
}
|
||||
];
|
||||
|
|
|
@ -1,11 +1,24 @@
|
|||
import { Component, signal } from '@angular/core';
|
||||
import { RouterOutlet } from '@angular/router';
|
||||
import { CalendarPreviousViewDirective, CalendarTodayDirective, CalendarNextViewDirective, CalendarMonthViewComponent, CalendarWeekViewComponent, CalendarDayViewComponent, CalendarDatePipe, DateAdapter, provideCalendar } from 'angular-calendar';
|
||||
import { adapterFactory } from 'angular-calendar/date-adapters/moment';
|
||||
import * as moment from 'moment';
|
||||
|
||||
export function momentAdapterFactory() {
|
||||
return adapterFactory(moment);
|
||||
};
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
imports: [RouterOutlet],
|
||||
imports: [RouterOutlet, CalendarPreviousViewDirective, CalendarTodayDirective, CalendarNextViewDirective, CalendarMonthViewComponent, CalendarWeekViewComponent, CalendarDayViewComponent, CalendarDatePipe],
|
||||
templateUrl: './app.html',
|
||||
styleUrl: './app.scss'
|
||||
styleUrl: './app.scss',
|
||||
providers: [
|
||||
provideCalendar({
|
||||
provide: DateAdapter,
|
||||
useFactory: momentAdapterFactory,
|
||||
}),
|
||||
],
|
||||
})
|
||||
export class App {
|
||||
protected readonly title = signal('frontend');
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
import { Component, EventEmitter, Input, Output, OnChanges, SimpleChanges, computed, effect, signal } from '@angular/core';
|
||||
import { FormBuilder, FormGroup, ReactiveFormsModule, Validators } from '@angular/forms';
|
||||
import { NgFor, NgIf } from '@angular/common';
|
||||
import oedb from '../../../oedb-types';
|
||||
import { OedbApi } from '../../services/oedb-api';
|
||||
import { JsonPipe } from '@angular/common';
|
||||
|
||||
@Component({
|
||||
selector: 'app-edit-form',
|
||||
standalone: true,
|
||||
imports: [ReactiveFormsModule, JsonPipe],
|
||||
templateUrl: './edit-form.html',
|
||||
styleUrl: './edit-form.scss'
|
||||
|
|
|
@ -3,6 +3,7 @@ import oedb_what_categories from '../../../oedb-types';
|
|||
|
||||
@Component({
|
||||
selector: 'app-all-events',
|
||||
standalone: true,
|
||||
imports: [],
|
||||
templateUrl: './all-events.html',
|
||||
styleUrl: './all-events.scss'
|
||||
|
|
59
frontend/src/app/pages/agenda/agenda.html
Normal file
59
frontend/src/app/pages/agenda/agenda.html
Normal file
|
@ -0,0 +1,59 @@
|
|||
<div class="agenda-container">
|
||||
<div class="agenda-header">
|
||||
<h1>Agenda des événements</h1>
|
||||
<p>Événements des 20 derniers jours (10 jours avant et 10 jours après aujourd'hui)</p>
|
||||
</div>
|
||||
|
||||
<div class="agenda-content">
|
||||
<div class="days-grid">
|
||||
@for (day of daysWithEvents; track day.date.getTime()) {
|
||||
<div class="day-card" [class.today]="isToday(day.date)" [class.past]="isPast(day.date)">
|
||||
<div class="day-header">
|
||||
<h3>{{ formatDate(day.date) }}</h3>
|
||||
<span class="event-count">{{ day.events.length }} événement(s)</span>
|
||||
</div>
|
||||
|
||||
<div class="events-list">
|
||||
@if (day.events.length === 0) {
|
||||
<p class="no-events">Aucun événement</p>
|
||||
} @else {
|
||||
@for (event of day.events; track event.id) {
|
||||
<div class="event-item" (click)="selectEvent(event)">
|
||||
<div class="event-time">{{ getEventTime(event) }}</div>
|
||||
<div class="event-title">{{ getEventTitle(event) }}</div>
|
||||
@if (event.properties.what) {
|
||||
<div class="event-type">{{ event.properties.what }}</div>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Panneau latéral pour les détails de l'événement -->
|
||||
@if (showSidePanel && selectedEvent) {
|
||||
<div class="side-panel">
|
||||
<div class="side-panel-header">
|
||||
<h2>Détails de l'événement</h2>
|
||||
<button class="close-btn" (click)="closeSidePanel()">×</button>
|
||||
</div>
|
||||
|
||||
<div class="side-panel-content">
|
||||
<app-edit-form
|
||||
[selected]="selectedEvent"
|
||||
(saved)="onEventSaved($event)"
|
||||
(created)="onEventCreated($event)"
|
||||
(deleted)="onEventDeleted($event)">
|
||||
</app-edit-form>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
<!-- Overlay pour fermer le panneau latéral -->
|
||||
@if (showSidePanel) {
|
||||
<div class="overlay" (click)="closeSidePanel()"></div>
|
||||
}
|
||||
</div>
|
216
frontend/src/app/pages/agenda/agenda.scss
Normal file
216
frontend/src/app/pages/agenda/agenda.scss
Normal file
|
@ -0,0 +1,216 @@
|
|||
.agenda-container {
|
||||
padding: 20px;
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.agenda-header {
|
||||
text-align: center;
|
||||
margin-bottom: 30px;
|
||||
|
||||
h1 {
|
||||
color: #333;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
p {
|
||||
color: #666;
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
|
||||
.agenda-content {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.days-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
.day-card {
|
||||
background: white;
|
||||
border: 1px solid #e0e0e0;
|
||||
border-radius: 8px;
|
||||
padding: 15px;
|
||||
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
||||
transition: all 0.3s ease;
|
||||
|
||||
&:hover {
|
||||
box-shadow: 0 4px 8px rgba(0,0,0,0.15);
|
||||
}
|
||||
|
||||
&.today {
|
||||
border-color: #007bff;
|
||||
background: #f8f9ff;
|
||||
|
||||
.day-header h3 {
|
||||
color: #007bff;
|
||||
}
|
||||
}
|
||||
|
||||
&.past {
|
||||
opacity: 0.7;
|
||||
background: #f5f5f5;
|
||||
}
|
||||
}
|
||||
|
||||
.day-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 15px;
|
||||
padding-bottom: 10px;
|
||||
border-bottom: 1px solid #eee;
|
||||
|
||||
h3 {
|
||||
margin: 0;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.event-count {
|
||||
background: #007bff;
|
||||
color: white;
|
||||
padding: 4px 8px;
|
||||
border-radius: 12px;
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
|
||||
.events-list {
|
||||
min-height: 50px;
|
||||
}
|
||||
|
||||
.no-events {
|
||||
color: #999;
|
||||
font-style: italic;
|
||||
text-align: center;
|
||||
margin: 20px 0;
|
||||
}
|
||||
|
||||
.event-item {
|
||||
background: #f8f9fa;
|
||||
border: 1px solid #e9ecef;
|
||||
border-radius: 6px;
|
||||
padding: 12px;
|
||||
margin-bottom: 8px;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
|
||||
&:hover {
|
||||
background: #e9ecef;
|
||||
border-color: #007bff;
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.event-time {
|
||||
font-size: 12px;
|
||||
color: #666;
|
||||
font-weight: 500;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.event-title {
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
margin-bottom: 4px;
|
||||
line-height: 1.3;
|
||||
}
|
||||
|
||||
.event-type {
|
||||
font-size: 12px;
|
||||
color: #007bff;
|
||||
background: #e7f3ff;
|
||||
padding: 2px 6px;
|
||||
border-radius: 4px;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
// Panneau latéral
|
||||
.side-panel {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
right: 0;
|
||||
width: 400px;
|
||||
height: 100vh;
|
||||
background: white;
|
||||
box-shadow: -2px 0 10px rgba(0,0,0,0.1);
|
||||
z-index: 1000;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.side-panel-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 20px;
|
||||
border-bottom: 1px solid #eee;
|
||||
background: #f8f9fa;
|
||||
|
||||
h2 {
|
||||
margin: 0;
|
||||
font-size: 18px;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.close-btn {
|
||||
background: none;
|
||||
border: none;
|
||||
font-size: 24px;
|
||||
cursor: pointer;
|
||||
color: #666;
|
||||
padding: 0;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 50%;
|
||||
|
||||
&:hover {
|
||||
background: #e9ecef;
|
||||
color: #333;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.side-panel-content {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.overlay {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
background: rgba(0,0,0,0.5);
|
||||
z-index: 999;
|
||||
}
|
||||
|
||||
// Responsive
|
||||
@media (max-width: 768px) {
|
||||
.agenda-container {
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.days-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.side-panel {
|
||||
width: 100vw;
|
||||
}
|
||||
}
|
23
frontend/src/app/pages/agenda/agenda.spec.ts
Normal file
23
frontend/src/app/pages/agenda/agenda.spec.ts
Normal file
|
@ -0,0 +1,23 @@
|
|||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { Agenda } from './agenda';
|
||||
|
||||
describe('Agenda', () => {
|
||||
let component: Agenda;
|
||||
let fixture: ComponentFixture<Agenda>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [Agenda]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(Agenda);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
166
frontend/src/app/pages/agenda/agenda.ts
Normal file
166
frontend/src/app/pages/agenda/agenda.ts
Normal file
|
@ -0,0 +1,166 @@
|
|||
import { Component, inject, OnInit } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { OedbApi } from '../../services/oedb-api';
|
||||
import { EditForm } from '../../forms/edit-form/edit-form';
|
||||
|
||||
interface Event {
|
||||
id: string;
|
||||
properties: {
|
||||
label?: string;
|
||||
name?: string;
|
||||
what?: string;
|
||||
start?: string;
|
||||
when?: string;
|
||||
stop?: string;
|
||||
description?: string;
|
||||
where?: string;
|
||||
};
|
||||
geometry?: {
|
||||
type: string;
|
||||
coordinates: [number, number];
|
||||
};
|
||||
}
|
||||
|
||||
interface DayEvents {
|
||||
date: Date;
|
||||
events: Event[];
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'app-agenda',
|
||||
standalone: true,
|
||||
imports: [CommonModule, EditForm],
|
||||
templateUrl: './agenda.html',
|
||||
styleUrl: './agenda.scss'
|
||||
})
|
||||
export class Agenda implements OnInit {
|
||||
private oedbApi = inject(OedbApi);
|
||||
|
||||
events: Event[] = [];
|
||||
daysWithEvents: DayEvents[] = [];
|
||||
selectedEvent: Event | null = null;
|
||||
showSidePanel = false;
|
||||
|
||||
ngOnInit() {
|
||||
this.loadEvents();
|
||||
}
|
||||
|
||||
loadEvents() {
|
||||
const today = new Date();
|
||||
const startDate = new Date(today);
|
||||
startDate.setDate(today.getDate() - 10);
|
||||
|
||||
const endDate = new Date(today);
|
||||
endDate.setDate(today.getDate() + 10);
|
||||
|
||||
const params = {
|
||||
start: `${startDate.toISOString().split('T')[0]}`,
|
||||
end: `${endDate.toISOString().split('T')[0]}`,
|
||||
limit: 1000
|
||||
};
|
||||
|
||||
this.oedbApi.getEvents(params).subscribe((response: any) => {
|
||||
this.events = Array.isArray(response?.features) ? response.features : [];
|
||||
this.organizeEventsByDay();
|
||||
});
|
||||
}
|
||||
|
||||
organizeEventsByDay() {
|
||||
const daysMap = new Map<string, DayEvents>();
|
||||
|
||||
// Initialiser les 20 jours
|
||||
for (let i = -10; i <= 10; i++) {
|
||||
const date = new Date();
|
||||
date.setDate(date.getDate() + i);
|
||||
const dateKey = date.toISOString().split('T')[0];
|
||||
daysMap.set(dateKey, {
|
||||
date: new Date(date),
|
||||
events: []
|
||||
});
|
||||
}
|
||||
|
||||
// Organiser les événements par jour
|
||||
this.events.forEach(event => {
|
||||
const eventDate = this.getEventDate(event);
|
||||
if (eventDate) {
|
||||
const dateKey = eventDate.toISOString().split('T')[0];
|
||||
const dayEvents = daysMap.get(dateKey);
|
||||
if (dayEvents) {
|
||||
dayEvents.events.push(event);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
this.daysWithEvents = Array.from(daysMap.values()).sort((a, b) =>
|
||||
a.date.getTime() - b.date.getTime()
|
||||
);
|
||||
}
|
||||
|
||||
getEventDate(event: Event): Date | null {
|
||||
const startDate = event.properties.start || event.properties.when;
|
||||
if (startDate) {
|
||||
return new Date(startDate);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
getEventTitle(event: Event): string {
|
||||
return event.properties.label || event.properties.name || 'Événement sans titre';
|
||||
}
|
||||
|
||||
getEventTime(event: Event): string {
|
||||
const startDate = event.properties.start || event.properties.when;
|
||||
if (startDate) {
|
||||
const date = new Date(startDate);
|
||||
return date.toLocaleTimeString('fr-FR', {
|
||||
hour: '2-digit',
|
||||
minute: '2-digit'
|
||||
});
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
selectEvent(event: Event) {
|
||||
this.selectedEvent = event;
|
||||
this.showSidePanel = true;
|
||||
}
|
||||
|
||||
closeSidePanel() {
|
||||
this.showSidePanel = false;
|
||||
this.selectedEvent = null;
|
||||
}
|
||||
|
||||
onEventSaved(event: any) {
|
||||
this.loadEvents(); // Recharger les événements après modification
|
||||
this.closeSidePanel();
|
||||
}
|
||||
|
||||
onEventCreated(event: any) {
|
||||
this.loadEvents(); // Recharger les événements après création
|
||||
this.closeSidePanel();
|
||||
}
|
||||
|
||||
onEventDeleted(event: any) {
|
||||
this.loadEvents(); // Recharger les événements après suppression
|
||||
this.closeSidePanel();
|
||||
}
|
||||
|
||||
isToday(date: Date): boolean {
|
||||
const today = new Date();
|
||||
return date.toDateString() === today.toDateString();
|
||||
}
|
||||
|
||||
isPast(date: Date): boolean {
|
||||
const today = new Date();
|
||||
today.setHours(0, 0, 0, 0);
|
||||
return date < today;
|
||||
}
|
||||
|
||||
formatDate(date: Date): string {
|
||||
return date.toLocaleDateString('fr-FR', {
|
||||
weekday: 'long',
|
||||
day: 'numeric',
|
||||
month: 'long'
|
||||
});
|
||||
}
|
||||
}
|
|
@ -6,6 +6,7 @@ import { OedbApi } from '../../services/oedb-api';
|
|||
import { UnlocatedEvents } from '../../shared/unlocated-events/unlocated-events';
|
||||
@Component({
|
||||
selector: 'app-home',
|
||||
standalone: true,
|
||||
imports: [
|
||||
Menu,
|
||||
AllEvents,
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
<menu>
|
||||
OpenEventDatabase
|
||||
<a routerLink="/agenda">agenda</a>
|
||||
<a href="/demo/stats">stats</a>
|
||||
<a href="https://source.cipherbliss.com/tykayn/oedb-backend">sources</a>
|
||||
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
import { Component } from '@angular/core';
|
||||
import oedb_what_categories from '../../../../oedb-types';
|
||||
import { RouterLink } from "@angular/router";
|
||||
|
||||
@Component({
|
||||
selector: 'app-menu',
|
||||
imports: [],
|
||||
standalone: true,
|
||||
imports: [RouterLink],
|
||||
templateUrl: './menu.html',
|
||||
styleUrl: './menu.scss'
|
||||
})
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue