From dfd9a4846fdd14087c01596a47f99e097a657f17 Mon Sep 17 00:00:00 2001
From: Arthur Monney <monneylobe@gmail.com>
Date: Tue, 18 Oct 2022 04:38:52 +0100
Subject: [PATCH 1/9] :recycle: refactoring components

---
 .../modules/authentication/authentication.module.ts |  2 --
 src/app/modules/dashboard/dashboard.module.ts       | 13 +++----------
 src/app/modules/design/design.module.ts             | 12 ++++++++++++
 src/app/modules/user/interfaces/user.interface.ts   |  2 +-
 4 files changed, 16 insertions(+), 13 deletions(-)
 create mode 100644 src/app/modules/design/design.module.ts

diff --git a/src/app/modules/authentication/authentication.module.ts b/src/app/modules/authentication/authentication.module.ts
index de22ff4..40acc9f 100644
--- a/src/app/modules/authentication/authentication.module.ts
+++ b/src/app/modules/authentication/authentication.module.ts
@@ -27,7 +27,5 @@ import { AuthEffects } from './store/auth.effects';
     SharedModule,
     StoreModule.forFeature(authFeatureKey, authReducer),
   ],
-  exports: [],
-  providers: [],
 })
 export class AuthenticationModule {}
diff --git a/src/app/modules/dashboard/dashboard.module.ts b/src/app/modules/dashboard/dashboard.module.ts
index b00f7f6..214e4cb 100644
--- a/src/app/modules/dashboard/dashboard.module.ts
+++ b/src/app/modules/dashboard/dashboard.module.ts
@@ -7,14 +7,7 @@ import { DashboardComponent } from './pages/dashboard/dashboard.component';
 import { dashboardRoutes } from './routes/dashboard.routes';
 
 @NgModule({
-  declarations: [
-    DashboardComponent
-  ],
-  imports: [
-    SharedModule,
-    RouterModule.forChild(dashboardRoutes),
-  ],
-  exports: [],
-  providers: [],
+  declarations: [DashboardComponent],
+  imports: [SharedModule, RouterModule.forChild(dashboardRoutes)],
 })
-export class DashboardModule { }
+export class DashboardModule {}
diff --git a/src/app/modules/design/design.module.ts b/src/app/modules/design/design.module.ts
new file mode 100644
index 0000000..fbfa64f
--- /dev/null
+++ b/src/app/modules/design/design.module.ts
@@ -0,0 +1,12 @@
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+
+
+
+@NgModule({
+  declarations: [],
+  imports: [
+    CommonModule
+  ]
+})
+export class DesignModule { }
diff --git a/src/app/modules/user/interfaces/user.interface.ts b/src/app/modules/user/interfaces/user.interface.ts
index 485103c..b68decd 100644
--- a/src/app/modules/user/interfaces/user.interface.ts
+++ b/src/app/modules/user/interfaces/user.interface.ts
@@ -20,7 +20,7 @@ export interface AuthResponse {
 
 export interface FromDate {
   date: Date;
-  timezone_type: number;
+  timezoneType: number;
   timezone: string;
 }
 

From a244979c1fcef0841e4e1b3dcb8305c2bca2beab Mon Sep 17 00:00:00 2001
From: Arthur Monney <monneylobe@gmail.com>
Date: Tue, 18 Oct 2022 05:04:14 +0100
Subject: [PATCH 2/9] update seo service

---
 src/app/shared/services/seo.service.ts | 178 +++++++++++++------------
 1 file changed, 91 insertions(+), 87 deletions(-)

diff --git a/src/app/shared/services/seo.service.ts b/src/app/shared/services/seo.service.ts
index d72c27a..472d7e0 100644
--- a/src/app/shared/services/seo.service.ts
+++ b/src/app/shared/services/seo.service.ts
@@ -28,97 +28,101 @@ export class SeoService implements OnDestroy {
   }
 
   private updateTitle(url: string): void {
-    this.title.setTitle(meta[url].title);
+    if (meta[url]) {
+      this.title.setTitle(meta[url].title);
+    }
   }
 
   private updateMeta(url: string): void {
-    const oldTagOgTitle = this.meta.getTag('property="og:title"');
-    const newTagOgTitle = {
-      property: 'og:title',
-      content: meta[url].title,
-    };
-    const oldTagTwitterTitle = this.meta.getTag('name="twitter:title"');
-    const newTagTwitterTitle = {
-      name: 'twitter:title',
-      content: meta[url].title,
-    };
-    const oldTagDescription = this.meta.getTag('name="description"');
-    const newTagDescription = {
-      name: 'description',
-      content: meta[url].description,
-    };
-    const oldTagOgDescription = this.meta.getTag('property="og:description"');
-    const newTagOgDescription = {
-      property: 'og:description',
-      content: meta[url].description,
-    };
-    const oldTagTwitterDescription = this.meta.getTag(
-      'property="og:description"'
-    );
-    const newTagTwitterDescription = {
-      property: 'og:description',
-      content: meta[url].description,
-    };
-    const oldTagOgImage = this.meta.getTag('property="og:image"');
-    const imageTag =
-      meta[url].metaTags?.['image'] ??
-      this.meta.getTag('property="og:image"')!.content;
-    const newTagOgImage = {
-      property: 'og:image',
-      content: imageTag,
-    };
-    const oldTagTwitterImage = this.meta.getTag('name="twitter:image"');
-    const newTagTwitterImage = {
-      name: 'twitter:image',
-      content: imageTag,
-    };
-    const oldTagOgUrl = this.meta.getTag('property="og:url"');
-    const newTagOgUrl = {
-      property: 'og:url',
-      content: meta[url].metaTags?.['og:url'],
-    };
-    const oldTagKeywords = this.meta.getTag('name="keywords"');
-    const newTagKeywords = {
-      name: 'keywords',
-      content: meta[url].keywords,
-    };
+    if (meta[url]) {
+      const oldTagOgTitle = this.meta.getTag('property="og:title"');
+      const newTagOgTitle = {
+        property: 'og:title',
+        content: meta[url].title,
+      };
+      const oldTagTwitterTitle = this.meta.getTag('name="twitter:title"');
+      const newTagTwitterTitle = {
+        name: 'twitter:title',
+        content: meta[url].title,
+      };
+      const oldTagDescription = this.meta.getTag('name="description"');
+      const newTagDescription = {
+        name: 'description',
+        content: meta[url].description,
+      };
+      const oldTagOgDescription = this.meta.getTag('property="og:description"');
+      const newTagOgDescription = {
+        property: 'og:description',
+        content: meta[url].description,
+      };
+      const oldTagTwitterDescription = this.meta.getTag(
+        'property="og:description"'
+      );
+      const newTagTwitterDescription = {
+        property: 'og:description',
+        content: meta[url].description,
+      };
+      const oldTagOgImage = this.meta.getTag('property="og:image"');
+      const imageTag =
+        meta[url].metaTags?.['image'] ??
+        this.meta.getTag('property="og:image"')!.content;
+      const newTagOgImage = {
+        property: 'og:image',
+        content: imageTag,
+      };
+      const oldTagTwitterImage = this.meta.getTag('name="twitter:image"');
+      const newTagTwitterImage = {
+        name: 'twitter:image',
+        content: imageTag,
+      };
+      const oldTagOgUrl = this.meta.getTag('property="og:url"');
+      const newTagOgUrl = {
+        property: 'og:url',
+        content: meta[url].metaTags?.['og:url'],
+      };
+      const oldTagKeywords = this.meta.getTag('name="keywords"');
+      const newTagKeywords = {
+        name: 'keywords',
+        content: meta[url].keywords,
+      };
 
-    // Update description
-    oldTagDescription
-      ? this.meta.updateTag(newTagDescription as MetaDefinition)
-      : this.meta.addTag(newTagDescription as MetaDefinition);
-    // Update og:description
-    oldTagOgDescription
-      ? this.meta.updateTag(newTagOgDescription as MetaDefinition)
-      : this.meta.addTag(newTagOgDescription as MetaDefinition);
-    // Update twitter:description
-    oldTagTwitterDescription
-      ? this.meta.updateTag(newTagTwitterDescription as MetaDefinition)
-      : this.meta.addTag(newTagTwitterDescription as MetaDefinition);
-    // Update og:title
-    oldTagOgTitle
-      ? this.meta.updateTag(newTagOgTitle as MetaDefinition)
-      : this.meta.addTag(newTagOgTitle as MetaDefinition);
-    // Update twitter:title
-    oldTagTwitterTitle
-      ? this.meta.updateTag(newTagTwitterTitle as MetaDefinition)
-      : this.meta.addTag(newTagTwitterTitle as MetaDefinition);
-    // Update og:image
-    oldTagOgImage
-      ? this.meta.updateTag(newTagOgImage as MetaDefinition)
-      : this.meta.addTag(newTagOgImage as MetaDefinition);
-    // Update twitter:image
-    oldTagTwitterImage
-      ? this.meta.updateTag(newTagTwitterImage as MetaDefinition)
-      : this.meta.addTag(newTagTwitterImage as MetaDefinition);
-    // Update og:url
-    oldTagOgUrl
-      ? this.meta.updateTag(newTagOgUrl as MetaDefinition)
-      : this.meta.addTag(newTagOgUrl as MetaDefinition);
-    // Update keywords
-    oldTagKeywords
-      ? this.meta.updateTag(newTagKeywords as MetaDefinition)
-      : this.meta.addTag(newTagKeywords as MetaDefinition);
+      // Update description
+      oldTagDescription
+        ? this.meta.updateTag(newTagDescription as MetaDefinition)
+        : this.meta.addTag(newTagDescription as MetaDefinition);
+      // Update og:description
+      oldTagOgDescription
+        ? this.meta.updateTag(newTagOgDescription as MetaDefinition)
+        : this.meta.addTag(newTagOgDescription as MetaDefinition);
+      // Update twitter:description
+      oldTagTwitterDescription
+        ? this.meta.updateTag(newTagTwitterDescription as MetaDefinition)
+        : this.meta.addTag(newTagTwitterDescription as MetaDefinition);
+      // Update og:title
+      oldTagOgTitle
+        ? this.meta.updateTag(newTagOgTitle as MetaDefinition)
+        : this.meta.addTag(newTagOgTitle as MetaDefinition);
+      // Update twitter:title
+      oldTagTwitterTitle
+        ? this.meta.updateTag(newTagTwitterTitle as MetaDefinition)
+        : this.meta.addTag(newTagTwitterTitle as MetaDefinition);
+      // Update og:image
+      oldTagOgImage
+        ? this.meta.updateTag(newTagOgImage as MetaDefinition)
+        : this.meta.addTag(newTagOgImage as MetaDefinition);
+      // Update twitter:image
+      oldTagTwitterImage
+        ? this.meta.updateTag(newTagTwitterImage as MetaDefinition)
+        : this.meta.addTag(newTagTwitterImage as MetaDefinition);
+      // Update og:url
+      oldTagOgUrl
+        ? this.meta.updateTag(newTagOgUrl as MetaDefinition)
+        : this.meta.addTag(newTagOgUrl as MetaDefinition);
+      // Update keywords
+      oldTagKeywords
+        ? this.meta.updateTag(newTagKeywords as MetaDefinition)
+        : this.meta.addTag(newTagKeywords as MetaDefinition);
+    }
   }
 
   ngOnDestroy() {

From f87f1938d9f7f814f2bf42fd47e6f6530dbb9ad6 Mon Sep 17 00:00:00 2001
From: Arthur Monney <monneylobe@gmail.com>
Date: Tue, 18 Oct 2022 05:05:05 +0100
Subject: [PATCH 3/9] setup design module

---
 src/app/core/routes/app.routing.ts            |  5 ++++
 src/app/modules/design/design.module.ts       | 14 ++++-----
 .../pages/calendar/calendar.component.html    |  1 +
 .../pages/calendar/calendar.component.scss    |  0
 .../pages/calendar/calendar.component.ts      |  9 ++++++
 .../modules/design/routes/design.routes.ts    | 30 +++++++++++++++++++
 6 files changed, 52 insertions(+), 7 deletions(-)
 create mode 100644 src/app/modules/design/pages/calendar/calendar.component.html
 create mode 100644 src/app/modules/design/pages/calendar/calendar.component.scss
 create mode 100644 src/app/modules/design/pages/calendar/calendar.component.ts
 create mode 100644 src/app/modules/design/routes/design.routes.ts

diff --git a/src/app/core/routes/app.routing.ts b/src/app/core/routes/app.routing.ts
index 8d72471..dca0241 100644
--- a/src/app/core/routes/app.routing.ts
+++ b/src/app/core/routes/app.routing.ts
@@ -18,5 +18,10 @@ export const ROUTES: Routes = [
         m => m.DashboardModule
       ),
   },
+  {
+    path: 'components',
+    loadChildren: () =>
+      import('@modules/design/design.module').then(m => m.DesignModule),
+  },
   { path: '**', pathMatch: 'full', component: NotFoundComponent },
 ];
diff --git a/src/app/modules/design/design.module.ts b/src/app/modules/design/design.module.ts
index fbfa64f..287b712 100644
--- a/src/app/modules/design/design.module.ts
+++ b/src/app/modules/design/design.module.ts
@@ -1,12 +1,12 @@
 import { NgModule } from '@angular/core';
-import { CommonModule } from '@angular/common';
-
+import { RouterModule } from '@angular/router';
 
+import { SharedModule } from '@app/shared/shared.module';
+import { designRoutes } from './routes/design.routes';
+import { CalendarComponent } from './pages/calendar/calendar.component';
 
 @NgModule({
-  declarations: [],
-  imports: [
-    CommonModule
-  ]
+  declarations: [CalendarComponent],
+  imports: [RouterModule.forChild(designRoutes), SharedModule],
 })
-export class DesignModule { }
+export class DesignModule {}
diff --git a/src/app/modules/design/pages/calendar/calendar.component.html b/src/app/modules/design/pages/calendar/calendar.component.html
new file mode 100644
index 0000000..6d8082c
--- /dev/null
+++ b/src/app/modules/design/pages/calendar/calendar.component.html
@@ -0,0 +1 @@
+<p>calendar works!</p>
diff --git a/src/app/modules/design/pages/calendar/calendar.component.scss b/src/app/modules/design/pages/calendar/calendar.component.scss
new file mode 100644
index 0000000..e69de29
diff --git a/src/app/modules/design/pages/calendar/calendar.component.ts b/src/app/modules/design/pages/calendar/calendar.component.ts
new file mode 100644
index 0000000..98a05c8
--- /dev/null
+++ b/src/app/modules/design/pages/calendar/calendar.component.ts
@@ -0,0 +1,9 @@
+import { Component } from '@angular/core';
+
+@Component({
+  templateUrl: './calendar.component.html',
+  styleUrls: ['./calendar.component.scss'],
+})
+export class CalendarComponent {
+  constructor() {}
+}
diff --git a/src/app/modules/design/routes/design.routes.ts b/src/app/modules/design/routes/design.routes.ts
new file mode 100644
index 0000000..189fb32
--- /dev/null
+++ b/src/app/modules/design/routes/design.routes.ts
@@ -0,0 +1,30 @@
+import { Routes } from '@angular/router';
+import { NgxPermissionsGuard } from 'ngx-permissions';
+
+import { AuthGuard } from '@app/core/guards/auth.guard';
+import { RoleGuard } from '@app/core/guards/role.guard';
+import { ADMIN_ROLE } from '@app/core/guards/user.roles';
+
+import { CpanelComponent } from '@app/shared/themes/layouts/cpanel/cpanel.component';
+import { CalendarComponent } from '../pages/calendar/calendar.component';
+
+export const designRoutes: Routes = [
+  {
+    path: '',
+    canActivate: [AuthGuard, RoleGuard],
+    component: CpanelComponent,
+    children: [
+      { path: '', redirectTo: 'calendar', pathMatch: 'full' },
+      {
+        path: 'calendar',
+        component: CalendarComponent,
+        canActivate: [NgxPermissionsGuard],
+        data: {
+          permissions: {
+            only: [ADMIN_ROLE],
+          },
+        },
+      },
+    ],
+  },
+];

From 5accddaa04592a8d47659676dee6e03baad73886 Mon Sep 17 00:00:00 2001
From: Arthur Monney <monneylobe@gmail.com>
Date: Tue, 18 Oct 2022 05:06:00 +0100
Subject: [PATCH 4/9] refcatoring

---
 src/app/modules/dashboard/dashboard.module.ts        |  2 +-
 .../shared/components/calendar/calendar.module.ts    | 12 ++++++++++++
 src/app/shared/shared.module.ts                      |  6 ++++--
 3 files changed, 17 insertions(+), 3 deletions(-)
 create mode 100644 src/app/shared/components/calendar/calendar.module.ts

diff --git a/src/app/modules/dashboard/dashboard.module.ts b/src/app/modules/dashboard/dashboard.module.ts
index 214e4cb..1551ee5 100644
--- a/src/app/modules/dashboard/dashboard.module.ts
+++ b/src/app/modules/dashboard/dashboard.module.ts
@@ -8,6 +8,6 @@ import { dashboardRoutes } from './routes/dashboard.routes';
 
 @NgModule({
   declarations: [DashboardComponent],
-  imports: [SharedModule, RouterModule.forChild(dashboardRoutes)],
+  imports: [RouterModule.forChild(dashboardRoutes), SharedModule],
 })
 export class DashboardModule {}
diff --git a/src/app/shared/components/calendar/calendar.module.ts b/src/app/shared/components/calendar/calendar.module.ts
new file mode 100644
index 0000000..ee453f2
--- /dev/null
+++ b/src/app/shared/components/calendar/calendar.module.ts
@@ -0,0 +1,12 @@
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+
+
+
+@NgModule({
+  declarations: [],
+  imports: [
+    CommonModule
+  ]
+})
+export class CalendarModule { }
diff --git a/src/app/shared/shared.module.ts b/src/app/shared/shared.module.ts
index 3f90227..9576144 100644
--- a/src/app/shared/shared.module.ts
+++ b/src/app/shared/shared.module.ts
@@ -9,6 +9,7 @@ import { HeadingModule } from './components/headings/heading.module';
 import { SkeletonModule } from './components/skeletons/skeleton.module';
 import { SnippetModule } from './components/snippets/snippet.module';
 import { TextareaModule } from './components/textarea/textarea.module';
+import { CalendarModule } from './components/calendar/calendar.module';
 
 import { ClickOutsideDirective } from './directives/click-outside.directive';
 import { StatusColorPipe } from './pipes/status-color.pipe';
@@ -17,13 +18,14 @@ import { StatusValuePipe } from './pipes/status-value.pipe';
 const DECLARATIONS = [ClickOutsideDirective, StatusColorPipe, StatusValuePipe];
 const MODULES = [
   AlertModule,
-  ThemeModule,
   ButtonModule,
-  InputsModule,
+  CalendarModule,
   HeadingModule,
+  InputsModule,
   SkeletonModule,
   SnippetModule,
   TextareaModule,
+  ThemeModule,
 ];
 
 @NgModule({

From e6fdb11b23b4910b4ef75ba35a9272a15d5fa5f4 Mon Sep 17 00:00:00 2001
From: Arthur Monney <monneylobe@gmail.com>
Date: Tue, 18 Oct 2022 05:06:14 +0100
Subject: [PATCH 5/9] :lipstick: Add components menu to sidebar

---
 src/app/modules/dashboard/navigation/admin.menu.ts | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/src/app/modules/dashboard/navigation/admin.menu.ts b/src/app/modules/dashboard/navigation/admin.menu.ts
index 9918ea2..9fe689d 100644
--- a/src/app/modules/dashboard/navigation/admin.menu.ts
+++ b/src/app/modules/dashboard/navigation/admin.menu.ts
@@ -45,6 +45,19 @@ export const adminMenu: Menu[] = [
       },
     ],
   },
+  {
+    group: $localize`Composants`,
+    items: [
+      {
+        title: $localize`Calendrier`,
+        svgPath: [
+          'M6.75 3v2.25M17.25 3v2.25M3 18.75V7.5a2.25 2.25 0 012.25-2.25h13.5A2.25 2.25 0 0121 7.5v11.25m-18 0A2.25 2.25 0 005.25 21h13.5A2.25 2.25 0 0021 18.75m-18 0v-7.5A2.25 2.25 0 015.25 9h13.5A2.25 2.25 0 0121 11.25v7.5m-9-6h.008v.008H12v-.008zM12 15h.008v.008H12V15zm0 2.25h.008v.008H12v-.008zM9.75 15h.008v.008H9.75V15zm0 2.25h.008v.008H9.75v-.008zM7.5 15h.008v.008H7.5V15zm0 2.25h.008v.008H7.5v-.008zm6.75-4.5h.008v.008h-.008v-.008zm0 2.25h.008v.008h-.008V15zm0 2.25h.008v.008h-.008v-.008zm2.25-4.5h.008v.008H16.5v-.008zm0 2.25h.008v.008H16.5V15z',
+        ],
+        link: '/components/calendar',
+        roles: [],
+      },
+    ],
+  },
   {
     group: $localize`Opérations`,
     items: [

From ede8a089e01c7a2ebec37790c0c4f51b7865dcaf Mon Sep 17 00:00:00 2001
From: Arthur Monney <monneylobe@gmail.com>
Date: Tue, 18 Oct 2022 06:57:58 +0100
Subject: [PATCH 6/9] wip

---
 .../pages/calendar/calendar.component.html    |   6 +-
 .../components/calendar/calendar.module.ts    |  13 +-
 .../components/calendar/calendar.service.ts   | 116 ++++++++++++++
 .../calendar/calendar/calendar.component.html |  22 +++
 .../calendar/calendar/calendar.component.scss |   0
 .../calendar/calendar/calendar.component.ts   |  57 +++++++
 .../shared/components/calendar/interfaces.ts  | 149 ++++++++++++++++++
 7 files changed, 355 insertions(+), 8 deletions(-)
 create mode 100644 src/app/shared/components/calendar/calendar.service.ts
 create mode 100644 src/app/shared/components/calendar/calendar/calendar.component.html
 create mode 100644 src/app/shared/components/calendar/calendar/calendar.component.scss
 create mode 100644 src/app/shared/components/calendar/calendar/calendar.component.ts
 create mode 100644 src/app/shared/components/calendar/interfaces.ts

diff --git a/src/app/modules/design/pages/calendar/calendar.component.html b/src/app/modules/design/pages/calendar/calendar.component.html
index 6d8082c..77de52a 100644
--- a/src/app/modules/design/pages/calendar/calendar.component.html
+++ b/src/app/modules/design/pages/calendar/calendar.component.html
@@ -1 +1,5 @@
-<p>calendar works!</p>
+<h2>Calendrier</h2>
+
+<div class="mt-10">
+  <tw-calendar></tw-calendar>
+</div>
diff --git a/src/app/shared/components/calendar/calendar.module.ts b/src/app/shared/components/calendar/calendar.module.ts
index ee453f2..217ea2d 100644
--- a/src/app/shared/components/calendar/calendar.module.ts
+++ b/src/app/shared/components/calendar/calendar.module.ts
@@ -1,12 +1,11 @@
-import { NgModule } from '@angular/core';
 import { CommonModule } from '@angular/common';
+import { NgModule } from '@angular/core';
 
-
+import { CalendarComponent } from './calendar/calendar.component';
 
 @NgModule({
-  declarations: [],
-  imports: [
-    CommonModule
-  ]
+  declarations: [CalendarComponent],
+  imports: [CommonModule],
+  exports: [CalendarComponent],
 })
-export class CalendarModule { }
+export class CalendarModule {}
diff --git a/src/app/shared/components/calendar/calendar.service.ts b/src/app/shared/components/calendar/calendar.service.ts
new file mode 100644
index 0000000..0a3deb5
--- /dev/null
+++ b/src/app/shared/components/calendar/calendar.service.ts
@@ -0,0 +1,116 @@
+import { Injectable } from '@angular/core';
+import { Observable, Subject } from 'rxjs';
+
+import {
+  ICalendarComponent,
+  IView,
+  CalendarMode,
+  QueryMode,
+} from './interfaces';
+
+@Injectable()
+export class CalendarService {
+  queryMode!: QueryMode;
+  currentDateChangedFromParent$!: Observable<Date>;
+  currentDateChangedFromChildren$!: Observable<Date>;
+  eventSourceChanged$!: Observable<void>;
+
+  private _currentDate!: Date;
+  private currentDateChangedFromParent = new Subject<Date>();
+  private currentDateChangedFromChildren = new Subject<Date>();
+  private eventSourceChanged = new Subject<void>();
+
+  constructor() {
+    this.currentDateChangedFromParent$ =
+      this.currentDateChangedFromParent.asObservable();
+    this.currentDateChangedFromChildren$ =
+      this.currentDateChangedFromChildren.asObservable();
+    this.eventSourceChanged$ = this.eventSourceChanged.asObservable();
+  }
+
+  setCurrentDate(val: Date, fromParent: boolean = false) {
+    this._currentDate = val;
+    if (fromParent) {
+      this.currentDateChangedFromParent.next(val);
+    } else {
+      this.currentDateChangedFromChildren.next(val);
+    }
+  }
+
+  get currentDate(): Date {
+    return this._currentDate;
+  }
+
+  rangeChanged(component: ICalendarComponent) {
+    if (this.queryMode === 'local') {
+      if (component.eventSource && component.onDataLoaded) {
+        component.onDataLoaded();
+      }
+    } else if (this.queryMode === 'remote') {
+      component.onRangeChanged.emit(component.range);
+    }
+  }
+
+  private getStep(mode: CalendarMode): {
+    years: number;
+    months: number;
+    days: number;
+  } {
+    switch (mode) {
+      case 'month':
+        return {
+          years: 0,
+          months: 1,
+          days: 0,
+        };
+      case 'week':
+        return {
+          years: 0,
+          months: 0,
+          days: 7,
+        };
+      case 'day':
+        return {
+          years: 0,
+          months: 0,
+          days: 1,
+        };
+    }
+  }
+
+  getAdjacentCalendarDate(mode: CalendarMode, direction: number): Date {
+    let calculateCalendarDate = new Date(this.currentDate.getTime());
+    const step = this.getStep(mode),
+      year = calculateCalendarDate.getFullYear() + direction * step.years,
+      month = calculateCalendarDate.getMonth() + direction * step.months,
+      date = calculateCalendarDate.getDate() + direction * step.days;
+
+    calculateCalendarDate.setFullYear(year, month, date);
+
+    if (mode === 'month') {
+      const firstDayInNextMonth = new Date(year, month + 1, 1);
+      if (firstDayInNextMonth.getTime() <= calculateCalendarDate.getTime()) {
+        calculateCalendarDate = new Date(
+          firstDayInNextMonth.getTime() - 24 * 60 * 60 * 1000
+        );
+      }
+    }
+    return calculateCalendarDate;
+  }
+
+  getAdjacentViewStartTime(
+    component: ICalendarComponent,
+    direction: number
+  ): Date {
+    const adjacentCalendarDate = this.getAdjacentCalendarDate(
+      component.mode,
+      direction
+    );
+
+    return component.getRange(adjacentCalendarDate).startTime;
+  }
+
+  loadEvents() {
+    this.eventSourceChanged.next();
+  }
+}
diff --git a/src/app/shared/components/calendar/calendar/calendar.component.html b/src/app/shared/components/calendar/calendar/calendar.component.html
new file mode 100644
index 0000000..174325f
--- /dev/null
+++ b/src/app/shared/components/calendar/calendar/calendar.component.html
@@ -0,0 +1,22 @@
+<ng-template #monthviewDefaultDisplayEventTemplate let-view="view" let-row="row" let-col="col">
+  {{ view.dates[row * 7 + col].label }}
+</ng-template>
+<ng-template 
+  #monthviewDefaultEventDetailTemplate 
+  let-showEventDetail="showEventDetail"
+  let-selectedDate="selectedDate" let-noEventsLabel="noEventsLabel">
+  <div class="event-detail-container" has-bouncing="false" *ngIf="showEventDetail" overflow-scroll="false">
+    <div class="event-detail-item" *ngFor="let event of selectedDate?.events" (click)="eventSelected(event)">
+      <span *ngIf="!event.allDay" class="monthview-eventdetail-timecolumn">
+        {{event.startTime | date: 'HH:mm'}}
+          -
+        {{event.endTime | date: 'HH:mm'}}
+      </span>
+      <span *ngIf="event.allDay" class="monthview-eventdetail-timecolumn">{{ allDayLabel }}</span>
+      <span class="event-detail">  |  {{ event.title }}</span>
+    </div>
+    <div class="event-detail-item" *ngIf="selectedDate?.events.length === 0">
+      <div class="no-events-label">{{ noEventsLabel }}</div>
+    </div>
+  </div>
+</ng-template>
\ No newline at end of file
diff --git a/src/app/shared/components/calendar/calendar/calendar.component.scss b/src/app/shared/components/calendar/calendar/calendar.component.scss
new file mode 100644
index 0000000..e69de29
diff --git a/src/app/shared/components/calendar/calendar/calendar.component.ts b/src/app/shared/components/calendar/calendar/calendar.component.ts
new file mode 100644
index 0000000..1d994c6
--- /dev/null
+++ b/src/app/shared/components/calendar/calendar/calendar.component.ts
@@ -0,0 +1,57 @@
+import {
+  Component,
+  EventEmitter,
+  Input,
+  OnInit,
+  Output,
+  TemplateRef,
+  Inject,
+  LOCALE_ID,
+} from '@angular/core';
+import { Subscription } from 'rxjs';
+
+import { IEvent, IRange, ITimeSelected } from '../interfaces';
+import { CalendarService } from '../calendar.service';
+
+@Component({
+  selector: 'tw-calendar',
+  templateUrl: './calendar.component.html',
+  styleUrls: ['./calendar.component.scss'],
+  providers: [CalendarService],
+})
+export class CalendarComponent {
+  @Input()
+  get currentDate(): Date {
+    return this._currentDate;
+  }
+
+  set currentDate(date: Date) {
+    if (!date) {
+      date = new Date();
+    }
+
+    this._currentDate = date;
+    this.calendarService.setCurrentDate(date, true);
+    this.onCurrentDateChanged.emit(this._currentDate);
+  }
+
+  @Input() locale = '';
+
+  @Output() onCurrentDateChanged = new EventEmitter<Date>();
+  @Output() onRangeChanged = new EventEmitter<IRange>();
+  @Output() onEventSelected = new EventEmitter<IEvent>();
+  @Output() onTimeSelected = new EventEmitter<ITimeSelected>();
+  @Output() onTitleChanged = new EventEmitter<string>();
+
+  private _currentDate!: Date;
+  private hourParts = 1;
+  private hourSegments = 1;
+  private currentDateChangedFromChildrenSubscription!: Subscription;
+
+  constructor(
+    private calendarService: CalendarService,
+    @Inject(LOCALE_ID) private appLocale: string
+  ) {
+    this.locale = appLocale;
+  }
+}
diff --git a/src/app/shared/components/calendar/interfaces.ts b/src/app/shared/components/calendar/interfaces.ts
new file mode 100644
index 0000000..6181329
--- /dev/null
+++ b/src/app/shared/components/calendar/interfaces.ts
@@ -0,0 +1,149 @@
+import { EventEmitter, TemplateRef } from '@angular/core';
+
+export interface IEvent {
+  allDay: boolean;
+  endTime: Date;
+  startTime: Date;
+  title: string;
+}
+
+export interface IRange {
+  startTime: Date;
+  endTime: Date;
+}
+
+export interface IView {}
+
+export interface IDayView extends IView {
+  allDayEvents: IDisplayAllDayEvent[];
+  rows: IDayViewRow[];
+}
+
+export interface IDayViewRow {
+  events: IDisplayEvent[];
+  time: Date;
+}
+
+export interface IMonthView extends IView {
+  dates: IMonthViewRow[];
+  dayHeaders: string[];
+}
+
+export interface IMonthViewRow {
+  current?: boolean;
+  date: Date;
+  events: IEvent[];
+  hasEvent?: boolean;
+  label: string;
+  secondary: boolean;
+  selected?: boolean;
+  disabled: boolean;
+}
+
+export interface IWeekView extends IView {
+  dates: IWeekViewDateRow[];
+  rows: IWeekViewRow[][];
+}
+
+export interface IWeekViewDateRow {
+  current?: boolean;
+  date: Date;
+  events: IDisplayEvent[];
+  hasEvent?: boolean;
+  selected?: boolean;
+  dayHeader: string;
+}
+
+export interface IWeekViewRow {
+  events: IDisplayEvent[];
+  time: Date;
+}
+
+export interface IDisplayEvent {
+  endIndex: number;
+  endOffset?: number;
+  event: IEvent;
+  startIndex: number;
+  startOffset?: number;
+  overlapNumber?: number;
+  position?: number;
+}
+
+export interface IDisplayWeekViewHeader {
+  viewDate: IWeekViewDateRow;
+}
+
+export interface IDisplayAllDayEvent {
+  event: IEvent;
+}
+
+export interface ICalendarComponent {
+  currentViewIndex: number;
+  direction: number;
+  eventSource: IEvent[];
+  getRange: (date: Date) => IRange;
+  getViewData: (date: Date) => IView;
+  mode: CalendarMode;
+  range: IRange;
+  view: IView;
+  onDataLoaded: () => void;
+  onRangeChanged: EventEmitter<IRange>;
+}
+
+export interface ITimeSelected {
+  events: IEvent[];
+  selectedTime: Date;
+  disabled: boolean;
+}
+
+export interface IMonthViewDisplayEventTemplateContext {
+  view: IView;
+  row: number;
+  col: number;
+}
+
+export interface IMonthViewEventDetailTemplateContext {
+  selectedDate: ITimeSelected;
+  noEventsLabel: string;
+}
+
+export interface IWeekViewAllDayEventSectionTemplateContext {
+  day: IWeekViewDateRow;
+  eventTemplate: TemplateRef<IDisplayAllDayEvent>;
+}
+
+export interface IWeekViewNormalEventSectionTemplateContext {
+  tm: IWeekViewRow;
+  eventTemplate: TemplateRef<IDisplayEvent>;
+}
+
+export interface IDayViewAllDayEventSectionTemplateContext {
+  alldayEvents: IDisplayAllDayEvent[];
+  eventTemplate: TemplateRef<IDisplayAllDayEvent>;
+}
+
+export interface IDayViewNormalEventSectionTemplateContext {
+  tm: IDayViewRow;
+  eventTemplate: TemplateRef<IDisplayEvent>;
+}
+
+export interface IDateFormatter {
+  formatMonthViewDay?: (date: Date) => string;
+  formatMonthViewDayHeader?: (date: Date) => string;
+  formatMonthViewTitle?: (date: Date) => string;
+  formatWeekViewDayHeader?: (date: Date) => string;
+  formatWeekViewTitle?: (date: Date) => string;
+  formatWeekViewHourColumn?: (date: Date) => string;
+  formatDayViewTitle?: (date: Date) => string;
+  formatDayViewHourColumn?: (date: Date) => string;
+}
+
+export type CalendarMode = 'day' | 'month' | 'week';
+
+export type QueryMode = 'local' | 'remote';
+
+export enum Step {
+  QuarterHour = 15,
+  HalfHour = 30,
+  Hour = 60,
+}

From b1b190d7f0d7dc5ff14f19a755d27b4ecafc2e70 Mon Sep 17 00:00:00 2001
From: Arthur Monney <monneylobe@gmail.com>
Date: Tue, 18 Oct 2022 08:13:22 +0100
Subject: [PATCH 7/9] :construction: wip

---
 .../components/calendar/calendar.module.ts    |   3 +-
 .../calendar/calendar/calendar.component.html |  47 +-
 .../calendar/calendar/calendar.component.ts   | 132 ++++-
 .../calendar/month/month-view.component.html  |   0
 .../calendar/month/month-view.component.ts    | 548 ++++++++++++++++++
 5 files changed, 721 insertions(+), 9 deletions(-)
 create mode 100644 src/app/shared/components/calendar/month/month-view.component.html
 create mode 100644 src/app/shared/components/calendar/month/month-view.component.ts

diff --git a/src/app/shared/components/calendar/calendar.module.ts b/src/app/shared/components/calendar/calendar.module.ts
index 217ea2d..ba3ab33 100644
--- a/src/app/shared/components/calendar/calendar.module.ts
+++ b/src/app/shared/components/calendar/calendar.module.ts
@@ -2,9 +2,10 @@ import { CommonModule } from '@angular/common';
 import { NgModule } from '@angular/core';
 
 import { CalendarComponent } from './calendar/calendar.component';
+import { MonthViewComponent } from './month/month-view.component';
 
 @NgModule({
-  declarations: [CalendarComponent],
+  declarations: [CalendarComponent, MonthViewComponent],
   imports: [CommonModule],
   exports: [CalendarComponent],
 })
diff --git a/src/app/shared/components/calendar/calendar/calendar.component.html b/src/app/shared/components/calendar/calendar/calendar.component.html
index 174325f..17e8448 100644
--- a/src/app/shared/components/calendar/calendar/calendar.component.html
+++ b/src/app/shared/components/calendar/calendar/calendar.component.html
@@ -1,16 +1,16 @@
-<ng-template #monthviewDefaultDisplayEventTemplate let-view="view" let-row="row" let-col="col">
+<ng-template #monthViewDefaultDisplayEventTemplate let-view="view" let-row="row" let-col="col">
   {{ view.dates[row * 7 + col].label }}
 </ng-template>
 <ng-template 
-  #monthviewDefaultEventDetailTemplate 
+  #monthViewDefaultEventDetailTemplate 
   let-showEventDetail="showEventDetail"
   let-selectedDate="selectedDate" let-noEventsLabel="noEventsLabel">
   <div class="event-detail-container" has-bouncing="false" *ngIf="showEventDetail" overflow-scroll="false">
     <div class="event-detail-item" *ngFor="let event of selectedDate?.events" (click)="eventSelected(event)">
       <span *ngIf="!event.allDay" class="monthview-eventdetail-timecolumn">
-        {{event.startTime | date: 'HH:mm'}}
+        {{ event.startTime | date: 'HH:mm' }}
           -
-        {{event.endTime | date: 'HH:mm'}}
+        {{ event.endTime | date: 'HH:mm' }}
       </span>
       <span *ngIf="event.allDay" class="monthview-eventdetail-timecolumn">{{ allDayLabel }}</span>
       <span class="event-detail">  |  {{ event.title }}</span>
@@ -19,4 +19,41 @@
       <div class="no-events-label">{{ noEventsLabel }}</div>
     </div>
   </div>
-</ng-template>
\ No newline at end of file
+</ng-template>
+<ng-template #defaultWeekViewHeaderTemplate let-viewDate="viewDate">
+  {{ viewDate.dayHeader }}
+</ng-template>
+<ng-template #defaultAllDayEventTemplate let-displayEvent="displayEvent">
+  <div class="calendar-event-inner">{{ displayEvent.event.title }}</div>
+</ng-template>
+<ng-template #defaultNormalEventTemplate let-displayEvent="displayEvent">
+  <div class="calendar-event-inner">{{ displayEvent.event.title }}</div>
+</ng-template>
+<ng-template #defaultWeekViewAllDayEventSectionTemplate let-day="day" let-eventTemplate="eventTemplate">
+  <div [ngClass]="{'calendar-event-wrap': day.events}" *ngIf="day.events"
+       [ngStyle]="{height: 25*day.events.length+'px'}">
+      <div *ngFor="let displayEvent of day.events" class="calendar-event" tappable
+           (click)="eventSelected(displayEvent.event)"
+           [ngStyle]="{top: 25*displayEvent.position+'px', width: 100*(displayEvent.endIndex-displayEvent.startIndex)+'%', height: '25px'}">
+          <ng-template [ngTemplateOutlet]="eventTemplate"
+                       [ngTemplateOutletContext]="{displayEvent:displayEvent}">
+          </ng-template>
+      </div>
+  </div>
+</ng-template>
+<ng-template #defaultNormalEventSectionTemplate let-tm="tm" let-hourParts="hourParts"
+              let-eventTemplate="eventTemplate">
+    <div [ngClass]="{'calendar-event-wrap': tm.events}" *ngIf="tm.events">
+        <div *ngFor="let displayEvent of tm.events" class="calendar-event" tappable
+              (click)="eventSelected(displayEvent.event)"
+              [ngStyle]="{top: (37*displayEvent.startOffset/hourParts)+'px',left: 100/displayEvent.overlapNumber*displayEvent.position+'%', width: 100/displayEvent.overlapNumber+'%', height: 37*(displayEvent.endIndex -displayEvent.startIndex - (displayEvent.endOffset + displayEvent.startOffset)/hourParts)+'px'}">
+            <ng-template [ngTemplateOutlet]="eventTemplate"
+                          [ngTemplateOutletContext]="{displayEvent:displayEvent}">
+            </ng-template>
+        </div>
+    </div>
+</ng-template>
+
+<div [ngSwitch]="calendarMode" class="{{ calendarMode }}view-container">
+  Le calendrier ici
+</div>
\ No newline at end of file
diff --git a/src/app/shared/components/calendar/calendar/calendar.component.ts b/src/app/shared/components/calendar/calendar/calendar.component.ts
index 1d994c6..2929970 100644
--- a/src/app/shared/components/calendar/calendar/calendar.component.ts
+++ b/src/app/shared/components/calendar/calendar/calendar.component.ts
@@ -7,10 +7,28 @@ import {
   TemplateRef,
   Inject,
   LOCALE_ID,
+  OnDestroy,
 } from '@angular/core';
 import { Subscription } from 'rxjs';
 
-import { IEvent, IRange, ITimeSelected } from '../interfaces';
+import {
+  CalendarMode,
+  IDateFormatter,
+  IDayViewAllDayEventSectionTemplateContext,
+  IDayViewNormalEventSectionTemplateContext,
+  IDisplayAllDayEvent,
+  IDisplayEvent,
+  IDisplayWeekViewHeader,
+  IEvent,
+  IMonthViewDisplayEventTemplateContext,
+  IMonthViewEventDetailTemplateContext,
+  IRange,
+  ITimeSelected,
+  IWeekViewAllDayEventSectionTemplateContext,
+  IWeekViewNormalEventSectionTemplateContext,
+  QueryMode,
+  Step,
+} from '../interfaces';
 import { CalendarService } from '../calendar.service';
 
 @Component({
@@ -19,7 +37,7 @@ import { CalendarService } from '../calendar.service';
   styleUrls: ['./calendar.component.scss'],
   providers: [CalendarService],
 })
-export class CalendarComponent {
+export class CalendarComponent implements OnInit, OnDestroy {
   @Input()
   get currentDate(): Date {
     return this._currentDate;
@@ -35,7 +53,46 @@ export class CalendarComponent {
     this.onCurrentDateChanged.emit(this._currentDate);
   }
 
+  @Input() eventSource: IEvent[] = [];
+  @Input() calendarMode: CalendarMode = 'month';
+  @Input() formatDay = 'd';
+  @Input() formatDayHeader = 'EEE';
+  @Input() formatDayTitle = 'MMMM dd, yyyy';
+  @Input() formatWeekTitle = "MMMM yyyy, 'Week' w";
+  @Input() formatMonthTitle = 'MMMM yyyy';
+  @Input() formatWeekViewDayHeader = 'EEE d';
+  @Input() formatHourColumn = 'ha';
+  @Input() showEventDetail = true;
+  @Input() startingDayMonth = 0;
+  @Input() startingDayWeek = 0;
+  @Input() allDayLabel = 'all day';
+  @Input() noEventsLabel = 'No Events';
+  @Input() queryMode: QueryMode = 'local';
+  @Input() step: Step = Step.Hour;
+  @Input() timeInterval = 60;
+  @Input() autoSelect = true;
+  @Input() markDisabled!: (date: Date) => boolean;
+  @Input()
+  monthViewDisplayEventTemplate!: TemplateRef<IMonthViewDisplayEventTemplateContext>;
+  @Input()
+  monthViewEventDetailTemplate!: TemplateRef<IMonthViewEventDetailTemplateContext>;
+  @Input() weekViewHeaderTemplate!: TemplateRef<IDisplayWeekViewHeader>;
+  @Input() weekViewAllDayEventTemplate!: TemplateRef<IDisplayAllDayEvent>;
+  @Input() weekViewNormalEventTemplate!: TemplateRef<IDisplayEvent>;
+  @Input() dayViewAllDayEventTemplate!: TemplateRef<IDisplayAllDayEvent>;
+  @Input() dayViewNormalEventTemplate!: TemplateRef<IDisplayEvent>;
+  @Input()
+  weekViewAllDayEventSectionTemplate!: TemplateRef<IWeekViewAllDayEventSectionTemplateContext>;
+  @Input()
+  weekViewNormalEventSectionTemplate!: TemplateRef<IWeekViewNormalEventSectionTemplateContext>;
+  @Input()
+  dayViewAllDayEventSectionTemplate!: TemplateRef<IDayViewAllDayEventSectionTemplateContext>;
+  @Input()
+  dayViewNormalEventSectionTemplate!: TemplateRef<IDayViewNormalEventSectionTemplateContext>;
+  @Input() dateFormatter!: IDateFormatter;
   @Input() locale = '';
+  @Input() startHour = 0;
+  @Input() endHour = 24;
 
   @Output() onCurrentDateChanged = new EventEmitter<Date>();
   @Output() onRangeChanged = new EventEmitter<IRange>();
@@ -46,7 +103,7 @@ export class CalendarComponent {
   private _currentDate!: Date;
   private hourParts = 1;
   private hourSegments = 1;
-  private currentDateChangedFromChildrenSubscription!: Subscription;
+  private currentDateChangedFromChildrenSubscription!: Subscription | null;
 
   constructor(
     private calendarService: CalendarService,
@@ -54,4 +111,73 @@ export class CalendarComponent {
   ) {
     this.locale = appLocale;
   }
+
+  ngOnInit() {
+    if (this.autoSelect) {
+      if (this.autoSelect.toString() === 'false') {
+        this.autoSelect = false;
+      } else {
+        this.autoSelect = true;
+      }
+    }
+    this.hourSegments = 60 / this.timeInterval;
+    this.hourParts = 60 / this.step;
+    if (this.hourParts <= this.hourSegments) {
+      this.hourParts = 1;
+    } else {
+      this.hourParts = this.hourParts / this.hourSegments;
+    }
+    this.startHour = parseInt(this.startHour.toString(), 10);
+    this.endHour = parseInt(this.endHour.toString(), 10);
+    this.calendarService.queryMode = this.queryMode;
+
+    this.currentDateChangedFromChildrenSubscription =
+      this.calendarService.currentDateChangedFromChildren$.subscribe(
+        currentDate => {
+          this._currentDate = currentDate;
+          this.onCurrentDateChanged.emit(currentDate);
+        }
+      );
+  }
+
+  ngOnDestroy() {
+    if (this.currentDateChangedFromChildrenSubscription) {
+      this.currentDateChangedFromChildrenSubscription.unsubscribe();
+      this.currentDateChangedFromChildrenSubscription = null;
+    }
+  }
+
+  rangeChanged(range: IRange) {
+    this.onRangeChanged.emit(range);
+  }
+
+  eventSelected(event: IEvent) {
+    this.onEventSelected.emit(event);
+  }
+
+  timeSelected(timeSelected: ITimeSelected) {
+    this.onTimeSelected.emit(timeSelected);
+  }
+
+  titleChanged(title: string) {
+    this.onTitleChanged.emit(title);
+  }
+
+  loadEvents() {
+    this.calendarService.loadEvents();
+  }
+
+  next() {
+    this.currentDate = this.calendarService.getAdjacentCalendarDate(
+      this.calendarMode,
+      1
+    );
+  }
+
+  previous() {
+    this.currentDate = this.calendarService.getAdjacentCalendarDate(
+      this.calendarMode,
+      -1
+    );
+  }
 }
diff --git a/src/app/shared/components/calendar/month/month-view.component.html b/src/app/shared/components/calendar/month/month-view.component.html
new file mode 100644
index 0000000..e69de29
diff --git a/src/app/shared/components/calendar/month/month-view.component.ts b/src/app/shared/components/calendar/month/month-view.component.ts
new file mode 100644
index 0000000..3ab1b05
--- /dev/null
+++ b/src/app/shared/components/calendar/month/month-view.component.ts
@@ -0,0 +1,548 @@
+import {
+  Component,
+  OnInit,
+  OnChanges,
+  Input,
+  Output,
+  EventEmitter,
+  SimpleChanges,
+  TemplateRef,
+} from '@angular/core';
+import { Subscription } from 'rxjs';
+import { DatePipe } from '@angular/common';
+
+import {
+  ICalendarComponent,
+  IEvent,
+  IMonthView,
+  IMonthViewRow,
+  ITimeSelected,
+  IRange,
+  CalendarMode,
+  IDateFormatter,
+  IMonthViewDisplayEventTemplateContext,
+} from '../interfaces';
+import { CalendarService } from '../calendar.service';
+
+@Component({
+  selector: 'month-view',
+  templateUrl: './month-view.component.html',
+})
+export class MonthViewComponent
+  implements OnInit, OnChanges, ICalendarComponent
+{
+  @Input()
+  monthViewDisplayEventTemplate!: TemplateRef<IMonthViewDisplayEventTemplateContext>;
+  @Input()
+  monthViewInactiveDisplayEventTemplate!: TemplateRef<IMonthViewDisplayEventTemplateContext>;
+  @Input()
+  monthViewEventDetailTemplate!: TemplateRef<IMonthViewDisplayEventTemplateContext>;
+
+  @Input() formatDay!: string;
+  @Input() formatDayHeader!: string;
+  @Input() formatMonthTitle!: string;
+  @Input() eventSource!: IEvent[];
+  @Input() startingDayMonth!: number;
+  @Input() showEventDetail!: boolean;
+  @Input() noEventsLabel!: string;
+  @Input() autoSelect = true;
+  @Input() markDisabled!: (date: Date) => boolean;
+  @Input() locale!: string;
+  @Input() dateFormatter!: IDateFormatter;
+  @Input() spaceBetween!: number;
+
+  @Output() onRangeChanged = new EventEmitter<IRange>();
+  @Output() onEventSelected = new EventEmitter<IEvent>();
+  @Output() onTimeSelected = new EventEmitter<ITimeSelected>(true);
+  @Output() onTitleChanged = new EventEmitter<string>(true);
+
+  public view!: IMonthView;
+  public currentViewIndex = 0;
+  public selectedDate!: IMonthViewRow;
+  public range!: IRange;
+  public mode: CalendarMode = 'month';
+  public direction = 0;
+
+  private moveOnSelected = false;
+  private inited = false;
+  private currentDateChangedFromParentSubscription!: Subscription | null;
+  private eventSourceChangedSubscription!: Subscription | null;
+  private formatDayLabel!: (date: Date) => string;
+  private formatDayHeaderLabel!: (date: Date) => string;
+  private formatTitle!: (date: Date) => string;
+
+  constructor(private calendarService: CalendarService) {}
+
+  static getDates(startDate: Date, n: number): Date[] {
+    const dates = new Array(n),
+      current = new Date(startDate.getTime());
+    let i = 0;
+    current.setHours(12); // Prevent repeated dates because of timezone bug
+    while (i < n) {
+      dates[i++] = new Date(current.getTime());
+      current.setDate(current.getDate() + 1);
+    }
+    return dates;
+  }
+
+  ngOnInit() {
+    if (this.dateFormatter && this.dateFormatter.formatMonthViewDay) {
+      this.formatDayLabel = this.dateFormatter.formatMonthViewDay;
+    } else {
+      const dayLabelDatePipe = new DatePipe('en-US');
+      this.formatDayLabel = (date: Date): string => {
+        return dayLabelDatePipe.transform(date, this.formatDay)!;
+      };
+    }
+
+    if (this.dateFormatter && this.dateFormatter.formatMonthViewDayHeader) {
+      this.formatDayHeaderLabel = this.dateFormatter.formatMonthViewDayHeader;
+    } else {
+      const datePipe = new DatePipe(this.locale);
+      this.formatDayHeaderLabel = (date: Date): string => {
+        return datePipe.transform(date, this.formatDayHeader)!;
+      };
+    }
+
+    if (this.dateFormatter && this.dateFormatter.formatMonthViewTitle) {
+      this.formatTitle = this.dateFormatter.formatMonthViewTitle;
+    } else {
+      const datePipe = new DatePipe(this.locale);
+      this.formatTitle = (date: Date) => {
+        return datePipe.transform(date, this.formatMonthTitle)!;
+      };
+    }
+
+    this.refreshView();
+    this.inited = true;
+
+    this.currentDateChangedFromParentSubscription =
+      this.calendarService.currentDateChangedFromParent$.subscribe(
+        currentDate => {
+          this.refreshView();
+        }
+      );
+
+    this.eventSourceChangedSubscription =
+      this.calendarService.eventSourceChanged$.subscribe(() => {
+        this.onDataLoaded();
+      });
+  }
+
+  ngOnDestroy() {
+    if (this.currentDateChangedFromParentSubscription) {
+      this.currentDateChangedFromParentSubscription.unsubscribe();
+      this.currentDateChangedFromParentSubscription = null;
+    }
+
+    if (this.eventSourceChangedSubscription) {
+      this.eventSourceChangedSubscription.unsubscribe();
+      this.eventSourceChangedSubscription = null;
+    }
+  }
+
+  ngOnChanges(changes: SimpleChanges) {
+    if (!this.inited) {
+      return;
+    }
+
+    const eventSourceChange = changes['eventSource'];
+    if (eventSourceChange && eventSourceChange.currentValue) {
+      this.onDataLoaded();
+    }
+  }
+
+  ngAfterViewInit() {
+    const title = this.getTitle();
+    this.onTitleChanged.emit(title);
+  }
+
+  move(direction: number) {
+    if (direction === 0) {
+      return;
+    }
+
+    this.direction = direction;
+    if (!this.moveOnSelected) {
+      const adjacentDate = this.calendarService.getAdjacentCalendarDate(
+        this.mode,
+        direction
+      );
+      this.calendarService.setCurrentDate(adjacentDate);
+    }
+    this.refreshView();
+    this.direction = 0;
+    this.moveOnSelected = false;
+  }
+
+  createDateObject(date: Date): IMonthViewRow {
+    let disabled = false;
+    if (this.markDisabled) {
+      disabled = this.markDisabled(date);
+    }
+
+    return {
+      date: date,
+      events: [],
+      label: this.formatDayLabel(date),
+      secondary: false,
+      disabled: disabled,
+    };
+  }
+
+  getViewData(startTime: Date): IMonthView {
+    const startDate = startTime,
+      date = startDate.getDate(),
+      month = (startDate.getMonth() + (date !== 1 ? 1 : 0)) % 12,
+      dates = MonthViewComponent.getDates(startDate, 42),
+      days: IMonthViewRow[] = [];
+
+    for (let i = 0; i < 42; i++) {
+      const dateObject = this.createDateObject(dates[i]);
+      dateObject.secondary = dates[i].getMonth() !== month;
+      days[i] = dateObject;
+    }
+
+    const dayHeaders: string[] = [];
+    for (let i = 0; i < 7; i++) {
+      dayHeaders.push(this.formatDayHeaderLabel(days[i].date));
+    }
+    return {
+      dates: days,
+      dayHeaders: dayHeaders,
+    };
+  }
+
+  getHighlightClass(date: IMonthViewRow): string {
+    let className = '';
+
+    if (date.hasEvent) {
+      if (date.secondary) {
+        className = 'monthview-secondary-with-event';
+      } else {
+        className = 'monthview-primary-with-event';
+      }
+    }
+
+    if (date.selected) {
+      if (className) {
+        className += ' ';
+      }
+      className += 'monthview-selected';
+    }
+
+    if (date.current) {
+      if (className) {
+        className += ' ';
+      }
+      className += 'monthview-current';
+    }
+
+    if (date.secondary) {
+      if (className) {
+        className += ' ';
+      }
+      className += 'text-muted';
+    }
+
+    if (date.disabled) {
+      if (className) {
+        className += ' ';
+      }
+      className += 'monthview-disabled';
+    }
+    return className;
+  }
+
+  getRange(currentDate: Date): IRange {
+    const year = currentDate.getFullYear(),
+      month = currentDate.getMonth(),
+      firstDayOfMonth = new Date(year, month, 1),
+      difference = this.startingDayMonth - firstDayOfMonth.getDay(),
+      numDisplayedFromPreviousMonth =
+        difference > 0 ? 7 - difference : -difference,
+      startDate = new Date(firstDayOfMonth.getTime());
+
+    if (numDisplayedFromPreviousMonth > 0) {
+      startDate.setDate(-numDisplayedFromPreviousMonth + 1);
+    }
+
+    const endDate = new Date(startDate.getTime());
+    endDate.setDate(endDate.getDate() + 42);
+
+    return {
+      startTime: startDate,
+      endTime: endDate,
+    };
+  }
+
+  onDataLoaded() {
+    const range = this.range,
+      eventSource = this.eventSource,
+      len = eventSource ? eventSource.length : 0,
+      startTime = range.startTime,
+      endTime = range.endTime,
+      utcStartTime = new Date(
+        Date.UTC(
+          startTime.getFullYear(),
+          startTime.getMonth(),
+          startTime.getDate()
+        )
+      ),
+      utcEndTime = new Date(
+        Date.UTC(endTime.getFullYear(), endTime.getMonth(), endTime.getDate())
+      ),
+      dates = this.view.dates,
+      oneDay = 86400000,
+      eps = 0.0006;
+
+    for (let r = 0; r < 42; r += 1) {
+      if (dates[r].hasEvent) {
+        dates[r].hasEvent = false;
+        dates[r].events = [];
+      }
+    }
+
+    for (let i = 0; i < len; i += 1) {
+      const event = eventSource[i],
+        eventStartTime = new Date(event.startTime.getTime()),
+        eventEndTime = new Date(event.endTime.getTime());
+      let st: Date, et: Date;
+
+      if (event.allDay) {
+        if (eventEndTime <= utcStartTime || eventStartTime >= utcEndTime) {
+          continue;
+        } else {
+          st = utcStartTime;
+          et = utcEndTime;
+        }
+      } else {
+        if (eventEndTime <= startTime || eventStartTime >= endTime) {
+          continue;
+        } else {
+          st = startTime;
+          et = endTime;
+        }
+      }
+
+      let timeDiff: number;
+      let timeDifferenceStart: number;
+      if (eventStartTime <= st) {
+        timeDifferenceStart = 0;
+      } else {
+        timeDiff = eventStartTime.getTime() - st.getTime();
+        if (!event.allDay) {
+          timeDiff =
+            timeDiff -
+            (eventStartTime.getTimezoneOffset() - st.getTimezoneOffset()) *
+              60000;
+        }
+        timeDifferenceStart = timeDiff / oneDay;
+      }
+
+      let timeDifferenceEnd: number;
+      if (eventEndTime >= et) {
+        timeDiff = et.getTime() - st.getTime();
+        if (!event.allDay) {
+          timeDiff =
+            timeDiff -
+            (et.getTimezoneOffset() - st.getTimezoneOffset()) * 60000;
+        }
+        timeDifferenceEnd = timeDiff / oneDay;
+      } else {
+        timeDiff = eventEndTime.getTime() - st.getTime();
+        if (!event.allDay) {
+          timeDiff =
+            timeDiff -
+            (eventEndTime.getTimezoneOffset() - st.getTimezoneOffset()) * 60000;
+        }
+        timeDifferenceEnd = timeDiff / oneDay;
+      }
+
+      let index = Math.floor(timeDifferenceStart);
+      while (index < timeDifferenceEnd - eps) {
+        dates[index].hasEvent = true;
+        let eventSet = dates[index].events;
+        if (eventSet) {
+          eventSet.push(event);
+        } else {
+          eventSet = [];
+          eventSet.push(event);
+          dates[index].events = eventSet;
+        }
+        index += 1;
+      }
+    }
+
+    for (let r = 0; r < 42; r += 1) {
+      if (dates[r].hasEvent) {
+        dates[r].events.sort(this.compareEvent);
+      }
+    }
+
+    if (this.autoSelect) {
+      let findSelected = false;
+      for (let r = 0; r < 42; r += 1) {
+        if (dates[r].selected) {
+          this.selectedDate = dates[r];
+          findSelected = true;
+          break;
+        }
+      }
+
+      if (findSelected) {
+        this.onTimeSelected.emit({
+          selectedTime: this.selectedDate.date,
+          events: this.selectedDate.events,
+          disabled: this.selectedDate.disabled,
+        });
+      }
+    }
+  }
+
+  refreshView() {
+    this.range = this.getRange(this.calendarService.currentDate);
+
+    if (this.inited) {
+      const title = this.getTitle();
+      this.onTitleChanged.emit(title);
+    }
+    this.view = this.getViewData(this.range.startTime);
+
+    this.updateCurrentView(this.range.startTime);
+    this.calendarService.rangeChanged(this);
+  }
+
+  getTitle(): string {
+    const currentViewStartDate = this.range.startTime,
+      date = currentViewStartDate.getDate(),
+      month = (currentViewStartDate.getMonth() + (date !== 1 ? 1 : 0)) % 12,
+      year =
+        currentViewStartDate.getFullYear() +
+        (date !== 1 && month === 0 ? 1 : 0),
+      headerDate = new Date(year, month, 1, 12, 0, 0, 0);
+    return this.formatTitle(headerDate);
+  }
+
+  private compareEvent(event1: IEvent, event2: IEvent): number {
+    if (event1.allDay) {
+      return 1;
+    } else if (event2.allDay) {
+      return -1;
+    } else {
+      return event1.startTime.getTime() - event2.startTime.getTime();
+    }
+  }
+
+  select(viewDate: IMonthViewRow) {
+    if (!this.view) {
+      return;
+    }
+
+    const selectedDate = viewDate.date,
+      events = viewDate.events;
+
+    if (!viewDate.disabled) {
+      const dates = this.view.dates,
+        currentCalendarDate = this.calendarService.currentDate,
+        currentMonth = currentCalendarDate.getMonth(),
+        currentYear = currentCalendarDate.getFullYear(),
+        selectedMonth = selectedDate.getMonth(),
+        selectedYear = selectedDate.getFullYear();
+      let direction = 0;
+
+      if (currentYear === selectedYear) {
+        if (currentMonth !== selectedMonth) {
+          direction = currentMonth < selectedMonth ? 1 : -1;
+        }
+      } else {
+        direction = currentYear < selectedYear ? 1 : -1;
+      }
+
+      this.calendarService.setCurrentDate(selectedDate);
+      if (direction === 0) {
+        const currentViewStartDate = this.range.startTime,
+          oneDay = 86400000,
+          selectedDayDifference = Math.floor(
+            (selectedDate.getTime() -
+              currentViewStartDate.getTime() -
+              (selectedDate.getTimezoneOffset() -
+                currentViewStartDate.getTimezoneOffset()) *
+                60000) /
+              oneDay
+          );
+
+        for (let r = 0; r < 42; r += 1) {
+          dates[r].selected = false;
+        }
+
+        if (selectedDayDifference >= 0 && selectedDayDifference < 42) {
+          dates[selectedDayDifference].selected = true;
+          this.selectedDate = dates[selectedDayDifference];
+        }
+      } else {
+        this.moveOnSelected = true;
+        this.move(direction);
+      }
+    }
+
+    this.onTimeSelected.emit({
+      selectedTime: selectedDate,
+      events: events,
+      disabled: viewDate.disabled,
+    });
+  }
+
+  updateCurrentView(currentViewStartDate: Date) {
+    const currentCalendarDate = this.calendarService.currentDate,
+      today = new Date(),
+      oneDay = 86400000,
+      selectedDayDifference = Math.floor(
+        (currentCalendarDate.getTime() -
+          currentViewStartDate.getTime() -
+          (currentCalendarDate.getTimezoneOffset() -
+            currentViewStartDate.getTimezoneOffset()) *
+            60000) /
+          oneDay
+      ),
+      currentDayDifference = Math.floor(
+        (today.getTime() -
+          currentViewStartDate.getTime() -
+          (today.getTimezoneOffset() -
+            currentViewStartDate.getTimezoneOffset()) *
+            60000) /
+          oneDay
+      ),
+      view = this.view;
+
+    for (let r = 0; r < 42; r += 1) {
+      view.dates[r].selected = false;
+    }
+
+    if (
+      selectedDayDifference >= 0 &&
+      selectedDayDifference < 42 &&
+      !view.dates[selectedDayDifference].disabled &&
+      (this.autoSelect || this.moveOnSelected)
+    ) {
+      view.dates[selectedDayDifference].selected = true;
+      this.selectedDate = view.dates[selectedDayDifference];
+    } else {
+      this.selectedDate = {
+        date: new Date(),
+        events: [],
+        label: 'null',
+        secondary: false,
+        disabled: false,
+      };
+    }
+
+    if (currentDayDifference >= 0 && currentDayDifference < 42) {
+      view.dates[currentDayDifference].current = true;
+    }
+  }
+
+  eventSelected(event: IEvent) {
+    this.onEventSelected.emit(event);
+  }
+}

From fcb98bb6707e13d685c28fcdad8c1aee1e57ef67 Mon Sep 17 00:00:00 2001
From: Arthur Monney <monneylobe@gmail.com>
Date: Tue, 18 Oct 2022 14:55:33 +0100
Subject: [PATCH 8/9] :construction: wip

---
 .../pages/calendar/calendar.component.html    |   5 +-
 .../pages/calendar/calendar.component.ts      |  13 +-
 .../components/calendar/calendar.service.ts   |   1 -
 .../calendar/calendar/calendar.component.html |  60 +++--
 .../calendar/calendar/calendar.component.ts   |  11 +
 .../shared/components/calendar/interfaces.ts  |   2 -
 .../calendar/month/month-view.component.html  | 227 ++++++++++++++++++
 .../calendar/month/month-view.component.ts    | 110 +++++----
 src/index.html                                |   2 +-
 9 files changed, 358 insertions(+), 73 deletions(-)

diff --git a/src/app/modules/design/pages/calendar/calendar.component.html b/src/app/modules/design/pages/calendar/calendar.component.html
index 77de52a..0970bb5 100644
--- a/src/app/modules/design/pages/calendar/calendar.component.html
+++ b/src/app/modules/design/pages/calendar/calendar.component.html
@@ -1,5 +1,8 @@
 <h2>Calendrier</h2>
 
 <div class="mt-10">
-  <tw-calendar></tw-calendar>
+  <tw-calendar
+    [currentDate]="calendar.currentDate"
+    monthStyle="overflow-hidden rounded-lg mb-20"
+  ></tw-calendar>
 </div>
diff --git a/src/app/modules/design/pages/calendar/calendar.component.ts b/src/app/modules/design/pages/calendar/calendar.component.ts
index 98a05c8..d2d3391 100644
--- a/src/app/modules/design/pages/calendar/calendar.component.ts
+++ b/src/app/modules/design/pages/calendar/calendar.component.ts
@@ -1,9 +1,18 @@
-import { Component } from '@angular/core';
+import { Component, OnInit, ViewEncapsulation } from '@angular/core';
 
 @Component({
   templateUrl: './calendar.component.html',
   styleUrls: ['./calendar.component.scss'],
+  encapsulation: ViewEncapsulation.None,
 })
-export class CalendarComponent {
+export class CalendarComponent implements OnInit {
+  public calendar!: any;
   constructor() {}
+
+  ngOnInit(): void {
+    this.calendar = {
+      mode: 'month',
+      currentDate: new Date(),
+    };
+  }
 }
diff --git a/src/app/shared/components/calendar/calendar.service.ts b/src/app/shared/components/calendar/calendar.service.ts
index 0a3deb5..149cf54 100644
--- a/src/app/shared/components/calendar/calendar.service.ts
+++ b/src/app/shared/components/calendar/calendar.service.ts
@@ -3,7 +3,6 @@ import { Observable, Subject } from 'rxjs';
 
 import {
   ICalendarComponent,
-  IView,
   CalendarMode,
   QueryMode,
 } from './interfaces';
diff --git a/src/app/shared/components/calendar/calendar/calendar.component.html b/src/app/shared/components/calendar/calendar/calendar.component.html
index 17e8448..19af189 100644
--- a/src/app/shared/components/calendar/calendar/calendar.component.html
+++ b/src/app/shared/components/calendar/calendar/calendar.component.html
@@ -1,8 +1,18 @@
-<ng-template #monthViewDefaultDisplayEventTemplate let-view="view" let-row="row" let-col="col">
-  {{ view.dates[row * 7 + col].label }}
+<ng-template #monthViewDefaultDisplayEventTemplate let-view="view">
+  <time [attr.datetime]="view.date" 
+        [ngClass]="{ 'flex h-6 w-6 items-center justify-center rounded-full bg-primary-600 font-semibold text-white' : view.current }"
+  >{{ view.label }}</time>
+  <ol class="mt-2" *ngIf="view.events.length > 0">
+    <li *ngFor="let event of view.events">
+      <a href="#" class="flex group">
+        <p class="flex-auto font-medium truncate text-slate-900 dark:text-white/75 group-hover:text-primary-600">{{ event.title }}</p>
+        <time [attr.datetime]="event.startTime" class="flex-none hidden ml-3 text-slate-500 group-hover:text-primary-600 xl:block">{{ event.startTime }}</time>
+      </a>
+    </li>
+  </ol>
 </ng-template>
-<ng-template 
-  #monthViewDefaultEventDetailTemplate 
+<ng-template
+  #monthViewDefaultEventDetailTemplate
   let-showEventDetail="showEventDetail"
   let-selectedDate="selectedDate" let-noEventsLabel="noEventsLabel">
   <div class="event-detail-container" has-bouncing="false" *ngIf="showEventDetail" overflow-scroll="false">
@@ -41,19 +51,37 @@
       </div>
   </div>
 </ng-template>
-<ng-template #defaultNormalEventSectionTemplate let-tm="tm" let-hourParts="hourParts"
-              let-eventTemplate="eventTemplate">
-    <div [ngClass]="{'calendar-event-wrap': tm.events}" *ngIf="tm.events">
-        <div *ngFor="let displayEvent of tm.events" class="calendar-event" tappable
-              (click)="eventSelected(displayEvent.event)"
-              [ngStyle]="{top: (37*displayEvent.startOffset/hourParts)+'px',left: 100/displayEvent.overlapNumber*displayEvent.position+'%', width: 100/displayEvent.overlapNumber+'%', height: 37*(displayEvent.endIndex -displayEvent.startIndex - (displayEvent.endOffset + displayEvent.startOffset)/hourParts)+'px'}">
-            <ng-template [ngTemplateOutlet]="eventTemplate"
-                          [ngTemplateOutletContext]="{displayEvent:displayEvent}">
-            </ng-template>
-        </div>
+<ng-template #defaultNormalEventSectionTemplate let-tm="tm" let-hourParts="hourParts" let-eventTemplate="eventTemplate">
+  <div [ngClass]="{'calendar-event-wrap': tm.events}" *ngIf="tm.events">
+    <div *ngFor="let displayEvent of tm.events" class="calendar-event" tappable
+        (click)="eventSelected(displayEvent.event)"
+        [ngStyle]="{top: (37*displayEvent.startOffset/hourParts)+'px',left: 100/displayEvent.overlapNumber*displayEvent.position+'%', width: 100/displayEvent.overlapNumber+'%', height: 37*(displayEvent.endIndex -displayEvent.startIndex - (displayEvent.endOffset + displayEvent.startOffset)/hourParts)+'px'}">
+        <ng-template [ngTemplateOutlet]="eventTemplate" 
+                      [ngTemplateOutletContext]="{displayEvent:displayEvent}">
+        </ng-template>
     </div>
+  </div>
 </ng-template>
 
-<div [ngSwitch]="calendarMode" class="{{ calendarMode }}view-container">
-  Le calendrier ici
+<div [ngSwitch]="calendarMode" class="{{ calendarMode }}-view">
+  <month-view *ngSwitchCase="'month'"
+    [formatDay]="formatDay"
+    [formatDayHeader]="formatDayHeader"
+    [formatMonthTitle]="formatMonthTitle"
+    [startingDayMonth]="startingDayMonth"
+    [showEventDetail]="showEventDetail"
+    [noEventsLabel]="noEventsLabel"
+    [autoSelect]="autoSelect"
+    [eventSource]="eventSource"
+    [markDisabled]="markDisabled"
+    [monthViewDisplayEventTemplate]="monthViewDisplayEventTemplate || monthViewDefaultDisplayEventTemplate"
+    [monthViewEventDetailTemplate]="monthViewEventDetailTemplate|| monthViewDefaultEventDetailTemplate"
+    [locale]="locale"
+    [dateFormatter]="dateFormatter"
+    [monthClass]="monthClass"
+    (onRangeChanged)="rangeChanged($event)"
+    (onEventSelected)="eventSelected($event)"
+    (onTimeSelected)="timeSelected($event)"
+    (onTitleChanged)="titleChanged($event)">
+  </month-view>
 </div>
\ No newline at end of file
diff --git a/src/app/shared/components/calendar/calendar/calendar.component.ts b/src/app/shared/components/calendar/calendar/calendar.component.ts
index 2929970..8f3840c 100644
--- a/src/app/shared/components/calendar/calendar/calendar.component.ts
+++ b/src/app/shared/components/calendar/calendar/calendar.component.ts
@@ -93,6 +93,10 @@ export class CalendarComponent implements OnInit, OnDestroy {
   @Input() locale = '';
   @Input() startHour = 0;
   @Input() endHour = 24;
+  @Input() styleClass!: string;
+  @Input('monthStyle') monthClass!: string;
+  @Input('weekStyle') weekClass!: string;
+  @Input('dayStyle') dayClass!: string;
 
   @Output() onCurrentDateChanged = new EventEmitter<Date>();
   @Output() onRangeChanged = new EventEmitter<IRange>();
@@ -105,11 +109,18 @@ export class CalendarComponent implements OnInit, OnDestroy {
   private hourSegments = 1;
   private currentDateChangedFromChildrenSubscription!: Subscription | null;
 
+  monthStyle!: string;
+  weekStyle!: string;
+  dayStyle!: string;
+
   constructor(
     private calendarService: CalendarService,
     @Inject(LOCALE_ID) private appLocale: string
   ) {
     this.locale = appLocale;
+    this.monthStyle = this.monthClass;
+    this.weekStyle = this.weekClass;
+    this.dayStyle = this.dayClass;
   }
 
   ngOnInit() {
diff --git a/src/app/shared/components/calendar/interfaces.ts b/src/app/shared/components/calendar/interfaces.ts
index 6181329..2393f50 100644
--- a/src/app/shared/components/calendar/interfaces.ts
+++ b/src/app/shared/components/calendar/interfaces.ts
@@ -98,8 +98,6 @@ export interface ITimeSelected {
 
 export interface IMonthViewDisplayEventTemplateContext {
   view: IView;
-  row: number;
-  col: number;
 }
 
 export interface IMonthViewEventDetailTemplateContext {
diff --git a/src/app/shared/components/calendar/month/month-view.component.html b/src/app/shared/components/calendar/month/month-view.component.html
index e69de29..dd7d69c 100644
--- a/src/app/shared/components/calendar/month/month-view.component.html
+++ b/src/app/shared/components/calendar/month/month-view.component.html
@@ -0,0 +1,227 @@
+<div>
+  <!-- <ng-template [ngTemplateOutlet]="monthViewEventDetailTemplate"
+               [ngTemplateOutletContext]="{showEventDetail:showEventDetail, selectedDate: selectedDate, noEventsLabel: noEventsLabel}">
+  </ng-template> -->
+  <div class="shadow ring-1 ring-black ring-opacity-5 lg:flex lg:flex-auto lg:flex-col" [ngClass]="monthClass">
+    <!-- Weekly Days -->
+    <div class="grid grid-cols-7 gap-px text-xs font-semibold leading-6 text-center bg-gray-200 border-b border-slate-300 text-slate-700 lg:flex-none dark:text-slate-300 dark:bg-gray-700 dark:border-gray-600">
+      <div *ngFor="let dayHeader of view.dayHeaders" class="flex justify-center py-2 bg-white dark:bg-gray-800">
+        <span class="uppercase">{{ dayHeader.slice(0, 1) }}</span>
+        <span class="sr-only sm:not-sr-only">{{ dayHeader.slice(1, 3) }}</span>
+      </div>
+    </div>
+    <div class="flex text-xs leading-6 bg-gray-200 text-slate-700 lg:flex-auto dark:bg-gray-600 dark:text-slate-300">
+      <!-- Desktop View -->
+      <div class="hidden w-full lg:grid lg:grid-cols-7 lg:grid-rows-6 lg:gap-px">
+        <div *ngFor="let view of view.dates" class="relative px-3 py-2" tappable [ngClass]="getHighlightClass(view)" (click)="select(view)">
+          <ng-template [ngTemplateOutlet]="monthViewDisplayEventTemplate"
+                        [ngTemplateOutletContext]="{ view }"></ng-template>
+        </div>
+      </div>
+      <!-- Mobile View -->
+      <div class="grid w-full grid-cols-7 grid-rows-6 gap-px isolate lg:hidden">
+        <!--
+          Always include: "flex h-14 flex-col py-2 px-3 hover:bg-gray-100 focus:z-10"
+          Is current month, include: "bg-white"
+          Is not current month, include: "bg-gray-50"
+          Is selected or is today, include: "font-semibold"
+          Is selected, include: "text-white"
+          Is not selected and is today, include: "text-primary-600"
+          Is not selected and is current month, and is not today, include: "text-gray-900"
+          Is not selected, is not current month, and is not today: "text-gray-500"
+        -->
+        <button type="button" class="flex flex-col px-3 py-2 text-gray-500 h-14 bg-gray-50 hover:bg-gray-100 focus:z-10">
+          <!--
+            Always include: "ml-auto"
+            Is selected, include: "flex h-6 w-6 items-center justify-center rounded-full"
+            Is selected and is today, include: "bg-primary-600"
+            Is selected and is not today, include: "bg-gray-900"
+          -->
+          <time datetime="2021-12-27" class="ml-auto">27</time>
+          <span class="sr-only">0 events</span>
+        </button>
+        <button type="button" class="flex flex-col px-3 py-2 text-gray-500 h-14 bg-gray-50 hover:bg-gray-100 focus:z-10">
+          <time datetime="2021-12-28" class="ml-auto">28</time>
+          <span class="sr-only">0 events</span>
+        </button>
+        <button type="button" class="flex flex-col px-3 py-2 text-gray-500 h-14 bg-gray-50 hover:bg-gray-100 focus:z-10">
+          <time datetime="2021-12-29" class="ml-auto">29</time>
+          <span class="sr-only">0 events</span>
+        </button>
+        <button type="button" class="flex flex-col px-3 py-2 text-gray-500 h-14 bg-gray-50 hover:bg-gray-100 focus:z-10">
+          <time datetime="2021-12-30" class="ml-auto">30</time>
+          <span class="sr-only">0 events</span>
+        </button>
+        <button type="button" class="flex flex-col px-3 py-2 text-gray-500 h-14 bg-gray-50 hover:bg-gray-100 focus:z-10">
+          <time datetime="2021-12-31" class="ml-auto">31</time>
+          <span class="sr-only">0 events</span>
+        </button>
+        <button type="button" class="flex flex-col px-3 py-2 text-gray-900 bg-white h-14 hover:bg-gray-100 focus:z-10">
+          <time datetime="2022-01-01" class="ml-auto">1</time>
+          <span class="sr-only">0 events</span>
+        </button>
+        <button type="button" class="flex flex-col px-3 py-2 text-gray-900 bg-white h-14 hover:bg-gray-100 focus:z-10">
+          <time datetime="2022-01-02" class="ml-auto">2</time>
+          <span class="sr-only">0 events</span>
+        </button>
+        <button type="button" class="flex flex-col px-3 py-2 text-gray-900 bg-white h-14 hover:bg-gray-100 focus:z-10">
+          <time datetime="2022-01-03" class="ml-auto">3</time>
+          <span class="sr-only">2 events</span>
+          <span class="-mx-0.5 mt-auto flex flex-wrap-reverse">
+            <span class="mx-0.5 mb-1 h-1.5 w-1.5 rounded-full bg-gray-400"></span>
+            <span class="mx-0.5 mb-1 h-1.5 w-1.5 rounded-full bg-gray-400"></span>
+          </span>
+        </button>
+        <button type="button" class="flex flex-col px-3 py-2 text-gray-900 bg-white h-14 hover:bg-gray-100 focus:z-10">
+          <time datetime="2022-01-04" class="ml-auto">4</time>
+          <span class="sr-only">0 events</span>
+        </button>
+        <button type="button" class="flex flex-col px-3 py-2 text-gray-900 bg-white h-14 hover:bg-gray-100 focus:z-10">
+          <time datetime="2022-01-05" class="ml-auto">5</time>
+          <span class="sr-only">0 events</span>
+        </button>
+        <button type="button" class="flex flex-col px-3 py-2 text-gray-900 bg-white h-14 hover:bg-gray-100 focus:z-10">
+          <time datetime="2022-01-06" class="ml-auto">6</time>
+          <span class="sr-only">0 events</span>
+        </button>
+        <button type="button" class="flex flex-col px-3 py-2 text-gray-900 bg-white h-14 hover:bg-gray-100 focus:z-10">
+          <time datetime="2022-01-07" class="ml-auto">7</time>
+          <span class="sr-only">1 event</span>
+          <span class="-mx-0.5 mt-auto flex flex-wrap-reverse">
+            <span class="mx-0.5 mb-1 h-1.5 w-1.5 rounded-full bg-gray-400"></span>
+          </span>
+        </button>
+        <button type="button" class="flex flex-col px-3 py-2 text-gray-900 bg-white h-14 hover:bg-gray-100 focus:z-10">
+          <time datetime="2022-01-08" class="ml-auto">8</time>
+          <span class="sr-only">0 events</span>
+        </button>
+        <button type="button" class="flex flex-col px-3 py-2 text-gray-900 bg-white h-14 hover:bg-gray-100 focus:z-10">
+          <time datetime="2022-01-09" class="ml-auto">9</time>
+          <span class="sr-only">0 events</span>
+        </button>
+        <button type="button" class="flex flex-col px-3 py-2 text-gray-900 bg-white h-14 hover:bg-gray-100 focus:z-10">
+          <time datetime="2022-01-10" class="ml-auto">10</time>
+          <span class="sr-only">0 events</span>
+        </button>
+        <button type="button" class="flex flex-col px-3 py-2 text-gray-900 bg-white h-14 hover:bg-gray-100 focus:z-10">
+          <time datetime="2022-01-11" class="ml-auto">11</time>
+          <span class="sr-only">0 events</span>
+        </button>
+        <button type="button" class="flex flex-col px-3 py-2 font-semibold bg-white text-primary-600 h-14 hover:bg-gray-100 focus:z-10">
+          <time datetime="2022-01-12" class="ml-auto">12</time>
+          <span class="sr-only">1 event</span>
+          <span class="-mx-0.5 mt-auto flex flex-wrap-reverse">
+            <span class="mx-0.5 mb-1 h-1.5 w-1.5 rounded-full bg-gray-400"></span>
+          </span>
+        </button>
+        <button type="button" class="flex flex-col px-3 py-2 text-gray-900 bg-white h-14 hover:bg-gray-100 focus:z-10">
+          <time datetime="2022-01-13" class="ml-auto">13</time>
+          <span class="sr-only">0 events</span>
+        </button>
+        <button type="button" class="flex flex-col px-3 py-2 text-gray-900 bg-white h-14 hover:bg-gray-100 focus:z-10">
+          <time datetime="2022-01-14" class="ml-auto">14</time>
+          <span class="sr-only">0 events</span>
+        </button>
+        <button type="button" class="flex flex-col px-3 py-2 text-gray-900 bg-white h-14 hover:bg-gray-100 focus:z-10">
+          <time datetime="2022-01-15" class="ml-auto">15</time>
+          <span class="sr-only">0 events</span>
+        </button>
+        <button type="button" class="flex flex-col px-3 py-2 text-gray-900 bg-white h-14 hover:bg-gray-100 focus:z-10">
+          <time datetime="2022-01-16" class="ml-auto">16</time>
+          <span class="sr-only">0 events</span>
+        </button>
+        <button type="button" class="flex flex-col px-3 py-2 text-gray-900 bg-white h-14 hover:bg-gray-100 focus:z-10">
+          <time datetime="2022-01-17" class="ml-auto">17</time>
+          <span class="sr-only">0 events</span>
+        </button>
+        <button type="button" class="flex flex-col px-3 py-2 text-gray-900 bg-white h-14 hover:bg-gray-100 focus:z-10">
+          <time datetime="2022-01-18" class="ml-auto">18</time>
+          <span class="sr-only">0 events</span>
+        </button>
+        <button type="button" class="flex flex-col px-3 py-2 text-gray-900 bg-white h-14 hover:bg-gray-100 focus:z-10">
+          <time datetime="2022-01-19" class="ml-auto">19</time>
+          <span class="sr-only">0 events</span>
+        </button>
+        <button type="button" class="flex flex-col px-3 py-2 text-gray-900 bg-white h-14 hover:bg-gray-100 focus:z-10">
+          <time datetime="2022-01-20" class="ml-auto">20</time>
+          <span class="sr-only">0 events</span>
+        </button>
+        <button type="button" class="flex flex-col px-3 py-2 text-gray-900 bg-white h-14 hover:bg-gray-100 focus:z-10">
+          <time datetime="2022-01-21" class="ml-auto">21</time>
+          <span class="sr-only">0 events</span>
+        </button>
+        <button type="button" class="flex flex-col px-3 py-2 font-semibold text-white bg-white h-14 hover:bg-gray-100 focus:z-10">
+          <time datetime="2022-01-22" class="flex items-center justify-center w-6 h-6 ml-auto bg-gray-900 rounded-full">22</time>
+          <span class="sr-only">2 events</span>
+          <span class="-mx-0.5 mt-auto flex flex-wrap-reverse">
+            <span class="mx-0.5 mb-1 h-1.5 w-1.5 rounded-full bg-gray-400"></span>
+            <span class="mx-0.5 mb-1 h-1.5 w-1.5 rounded-full bg-gray-400"></span>
+          </span>
+        </button>
+        <button type="button" class="flex flex-col px-3 py-2 text-gray-900 bg-white h-14 hover:bg-gray-100 focus:z-10">
+          <time datetime="2022-01-23" class="ml-auto">23</time>
+          <span class="sr-only">0 events</span>
+        </button>
+        <button type="button" class="flex flex-col px-3 py-2 text-gray-900 bg-white h-14 hover:bg-gray-100 focus:z-10">
+          <time datetime="2022-01-24" class="ml-auto">24</time>
+          <span class="sr-only">0 events</span>
+        </button>
+        <button type="button" class="flex flex-col px-3 py-2 text-gray-900 bg-white h-14 hover:bg-gray-100 focus:z-10">
+          <time datetime="2022-01-25" class="ml-auto">25</time>
+          <span class="sr-only">0 events</span>
+        </button>
+        <button type="button" class="flex flex-col px-3 py-2 text-gray-900 bg-white h-14 hover:bg-gray-100 focus:z-10">
+          <time datetime="2022-01-26" class="ml-auto">26</time>
+          <span class="sr-only">0 events</span>
+        </button>
+        <button type="button" class="flex flex-col px-3 py-2 text-gray-900 bg-white h-14 hover:bg-gray-100 focus:z-10">
+          <time datetime="2022-01-27" class="ml-auto">27</time>
+          <span class="sr-only">0 events</span>
+        </button>
+        <button type="button" class="flex flex-col px-3 py-2 text-gray-900 bg-white h-14 hover:bg-gray-100 focus:z-10">
+          <time datetime="2022-01-28" class="ml-auto">28</time>
+          <span class="sr-only">0 events</span>
+        </button>
+        <button type="button" class="flex flex-col px-3 py-2 text-gray-900 bg-white h-14 hover:bg-gray-100 focus:z-10">
+          <time datetime="2022-01-29" class="ml-auto">29</time>
+          <span class="sr-only">0 events</span>
+        </button>
+        <button type="button" class="flex flex-col px-3 py-2 text-gray-900 bg-white h-14 hover:bg-gray-100 focus:z-10">
+          <time datetime="2022-01-30" class="ml-auto">30</time>
+          <span class="sr-only">0 events</span>
+        </button>
+        <button type="button" class="flex flex-col px-3 py-2 text-gray-900 bg-white h-14 hover:bg-gray-100 focus:z-10">
+          <time datetime="2022-01-31" class="ml-auto">31</time>
+          <span class="sr-only">0 events</span>
+        </button>
+        <button type="button" class="flex flex-col px-3 py-2 text-gray-500 h-14 bg-gray-50 hover:bg-gray-100 focus:z-10">
+          <time datetime="2022-02-01" class="ml-auto">1</time>
+          <span class="sr-only">0 events</span>
+        </button>
+        <button type="button" class="flex flex-col px-3 py-2 text-gray-500 h-14 bg-gray-50 hover:bg-gray-100 focus:z-10">
+          <time datetime="2022-02-02" class="ml-auto">2</time>
+          <span class="sr-only">0 events</span>
+        </button>
+        <button type="button" class="flex flex-col px-3 py-2 text-gray-500 h-14 bg-gray-50 hover:bg-gray-100 focus:z-10">
+          <time datetime="2022-02-03" class="ml-auto">3</time>
+          <span class="sr-only">0 events</span>
+        </button>
+        <button type="button" class="flex flex-col px-3 py-2 text-gray-500 h-14 bg-gray-50 hover:bg-gray-100 focus:z-10">
+          <time datetime="2022-02-04" class="ml-auto">4</time>
+          <span class="sr-only">1 event</span>
+          <span class="-mx-0.5 mt-auto flex flex-wrap-reverse">
+            <span class="mx-0.5 mb-1 h-1.5 w-1.5 rounded-full bg-gray-400"></span>
+          </span>
+        </button>
+        <button type="button" class="flex flex-col px-3 py-2 text-gray-500 h-14 bg-gray-50 hover:bg-gray-100 focus:z-10">
+          <time datetime="2022-02-05" class="ml-auto">5</time>
+          <span class="sr-only">0 events</span>
+        </button>
+        <button type="button" class="flex flex-col px-3 py-2 text-gray-500 h-14 bg-gray-50 hover:bg-gray-100 focus:z-10">
+          <time datetime="2022-02-06" class="ml-auto">6</time>
+          <span class="sr-only">0 events</span>
+        </button>
+      </div>
+    </div>
+  </div>
+</div>
\ No newline at end of file
diff --git a/src/app/shared/components/calendar/month/month-view.component.ts b/src/app/shared/components/calendar/month/month-view.component.ts
index 3ab1b05..1c4aa7e 100644
--- a/src/app/shared/components/calendar/month/month-view.component.ts
+++ b/src/app/shared/components/calendar/month/month-view.component.ts
@@ -36,7 +36,9 @@ export class MonthViewComponent
   @Input()
   monthViewInactiveDisplayEventTemplate!: TemplateRef<IMonthViewDisplayEventTemplateContext>;
   @Input()
-  monthViewEventDetailTemplate!: TemplateRef<IMonthViewDisplayEventTemplateContext>;
+  monthViewEventDetailTemplate!:
+    | TemplateRef<IMonthViewDisplayEventTemplateContext>
+    | any;
 
   @Input() formatDay!: string;
   @Input() formatDayHeader!: string;
@@ -50,6 +52,7 @@ export class MonthViewComponent
   @Input() locale!: string;
   @Input() dateFormatter!: IDateFormatter;
   @Input() spaceBetween!: number;
+  @Input() monthClass!: string;
 
   @Output() onRangeChanged = new EventEmitter<IRange>();
   @Output() onEventSelected = new EventEmitter<IEvent>();
@@ -82,6 +85,7 @@ export class MonthViewComponent
       dates[i++] = new Date(current.getTime());
       current.setDate(current.getDate() + 1);
     }
+
     return dates;
   }
 
@@ -117,12 +121,9 @@ export class MonthViewComponent
     this.inited = true;
 
     this.currentDateChangedFromParentSubscription =
-      this.calendarService.currentDateChangedFromParent$.subscribe(
-        currentDate => {
-          this.refreshView();
-        }
-      );
-
+      this.calendarService.currentDateChangedFromParent$.subscribe(() => {
+        this.refreshView();
+      });
     this.eventSourceChangedSubscription =
       this.calendarService.eventSourceChanged$.subscribe(() => {
         this.onDataLoaded();
@@ -191,11 +192,11 @@ export class MonthViewComponent
   }
 
   getViewData(startTime: Date): IMonthView {
-    const startDate = startTime,
-      date = startDate.getDate(),
-      month = (startDate.getMonth() + (date !== 1 ? 1 : 0)) % 12,
-      dates = MonthViewComponent.getDates(startDate, 42),
-      days: IMonthViewRow[] = [];
+    const startDate = startTime;
+    const date = startDate.getDate();
+    const month = (startDate.getMonth() + (date !== 1 ? 1 : 0)) % 12;
+    const dates = MonthViewComponent.getDates(startDate, 42);
+    const days: IMonthViewRow[] = [];
 
     for (let i = 0; i < 42; i++) {
       const dateObject = this.createDateObject(dates[i]);
@@ -207,6 +208,7 @@ export class MonthViewComponent
     for (let i = 0; i < 7; i++) {
       dayHeaders.push(this.formatDayHeaderLabel(days[i].date));
     }
+
     return {
       dates: days,
       dayHeaders: dayHeaders,
@@ -218,9 +220,9 @@ export class MonthViewComponent
 
     if (date.hasEvent) {
       if (date.secondary) {
-        className = 'monthview-secondary-with-event';
+        className = 'secondary-with-event';
       } else {
-        className = 'monthview-primary-with-event';
+        className = 'primary-with-event';
       }
     }
 
@@ -228,40 +230,48 @@ export class MonthViewComponent
       if (className) {
         className += ' ';
       }
-      className += 'monthview-selected';
+      className += 'selected';
     }
 
     if (date.current) {
       if (className) {
         className += ' ';
       }
-      className += 'monthview-current';
+      className += 'current';
     }
 
     if (date.secondary) {
       if (className) {
         className += ' ';
       }
-      className += 'text-muted';
+      className +=
+        'bg-gray-50 text-slate-500 dark:text-slate-400 dark:bg-gray-700';
+    } else {
+      if (className) {
+        className += ' ';
+      }
+      className +=
+        'bg-white text-slate-700 dark:bg-gray-800 dark:text-slate-300';
     }
 
     if (date.disabled) {
       if (className) {
         className += ' ';
       }
-      className += 'monthview-disabled';
+      className += 'disabled cursor-disabled bg-gray-100 dark:bg-gray-600';
     }
+
     return className;
   }
 
   getRange(currentDate: Date): IRange {
-    const year = currentDate.getFullYear(),
-      month = currentDate.getMonth(),
-      firstDayOfMonth = new Date(year, month, 1),
-      difference = this.startingDayMonth - firstDayOfMonth.getDay(),
-      numDisplayedFromPreviousMonth =
-        difference > 0 ? 7 - difference : -difference,
-      startDate = new Date(firstDayOfMonth.getTime());
+    const year = currentDate.getFullYear();
+    const month = currentDate.getMonth();
+    const firstDayOfMonth = new Date(year, month, 1);
+    const difference = this.startingDayMonth - firstDayOfMonth.getDay();
+    const numDisplayedFromPreviousMonth =
+      difference > 0 ? 7 - difference : -difference;
+    const startDate = new Date(firstDayOfMonth.getTime());
 
     if (numDisplayedFromPreviousMonth > 0) {
       startDate.setDate(-numDisplayedFromPreviousMonth + 1);
@@ -414,13 +424,13 @@ export class MonthViewComponent
   }
 
   getTitle(): string {
-    const currentViewStartDate = this.range.startTime,
-      date = currentViewStartDate.getDate(),
-      month = (currentViewStartDate.getMonth() + (date !== 1 ? 1 : 0)) % 12,
-      year =
-        currentViewStartDate.getFullYear() +
-        (date !== 1 && month === 0 ? 1 : 0),
-      headerDate = new Date(year, month, 1, 12, 0, 0, 0);
+    const currentViewStartDate = this.range.startTime;
+    const date = currentViewStartDate.getDate();
+    const month = (currentViewStartDate.getMonth() + (date !== 1 ? 1 : 0)) % 12;
+    const year =
+      currentViewStartDate.getFullYear() + (date !== 1 && month === 0 ? 1 : 0);
+    const headerDate = new Date(year, month, 1, 12, 0, 0, 0);
+
     return this.formatTitle(headerDate);
   }
 
@@ -439,16 +449,16 @@ export class MonthViewComponent
       return;
     }
 
-    const selectedDate = viewDate.date,
-      events = viewDate.events;
+    const selectedDate = viewDate.date;
+    const events = viewDate.events;
 
     if (!viewDate.disabled) {
-      const dates = this.view.dates,
-        currentCalendarDate = this.calendarService.currentDate,
-        currentMonth = currentCalendarDate.getMonth(),
-        currentYear = currentCalendarDate.getFullYear(),
-        selectedMonth = selectedDate.getMonth(),
-        selectedYear = selectedDate.getFullYear();
+      const dates = this.view.dates;
+      const currentCalendarDate = this.calendarService.currentDate;
+      const currentMonth = currentCalendarDate.getMonth();
+      const currentYear = currentCalendarDate.getFullYear();
+      const selectedMonth = selectedDate.getMonth();
+      const selectedYear = selectedDate.getFullYear();
       let direction = 0;
 
       if (currentYear === selectedYear) {
@@ -461,16 +471,16 @@ export class MonthViewComponent
 
       this.calendarService.setCurrentDate(selectedDate);
       if (direction === 0) {
-        const currentViewStartDate = this.range.startTime,
-          oneDay = 86400000,
-          selectedDayDifference = Math.floor(
-            (selectedDate.getTime() -
-              currentViewStartDate.getTime() -
-              (selectedDate.getTimezoneOffset() -
-                currentViewStartDate.getTimezoneOffset()) *
-                60000) /
-              oneDay
-          );
+        const currentViewStartDate = this.range.startTime;
+        const oneDay = 86400000;
+        const selectedDayDifference = Math.floor(
+          (selectedDate.getTime() -
+            currentViewStartDate.getTime() -
+            (selectedDate.getTimezoneOffset() -
+              currentViewStartDate.getTimezoneOffset()) *
+              60000) /
+            oneDay
+        );
 
         for (let r = 0; r < 42; r += 1) {
           dates[r].selected = false;
diff --git a/src/index.html b/src/index.html
index 1be3ff3..e045faf 100644
--- a/src/index.html
+++ b/src/index.html
@@ -29,7 +29,7 @@
   <link href="https://fonts.googleapis.com/css2?family=Roboto+Mono:wght@100;300;400;500;600;700&display=swap" rel="stylesheet">
   <link rel="stylesheet" href="https://rsms.me/inter/inter.css">
 </head>
-<body class="font-sans antialiased text-slate-500">
+<body class="font-sans antialiased text-slate-500 dark:text-slate-400">
   <admin-root></admin-root>
 </body>
 </html>

From 69afdff2c3e4f19d5cbe24db0f32290469232e9d Mon Sep 17 00:00:00 2001
From: Arthur Monney <monneylobe@gmail.com>
Date: Tue, 25 Oct 2022 13:04:55 +0100
Subject: [PATCH 9/9] :sparkles: Finish calendar month view

---
 .../calendar/calendar/calendar.component.html |  16 ++
 .../calendar/calendar/calendar.component.ts   |   2 +
 .../calendar/month/month-view.component.html  | 205 +-----------------
 .../calendar/month/month-view.component.ts    |   2 +
 4 files changed, 24 insertions(+), 201 deletions(-)

diff --git a/src/app/shared/components/calendar/calendar/calendar.component.html b/src/app/shared/components/calendar/calendar/calendar.component.html
index 19af189..5152a85 100644
--- a/src/app/shared/components/calendar/calendar/calendar.component.html
+++ b/src/app/shared/components/calendar/calendar/calendar.component.html
@@ -11,6 +11,21 @@
     </li>
   </ol>
 </ng-template>
+<ng-template #monthViewDefaultDisplayResponsiveEventTemplate let-view="view">
+  <time [attr.datetime]="view.date" 
+        [ngClass]="{ 'flex h-6 w-6 items-center justify-center rounded-full bg-primary-600 font-semibold text-white' : view.current }"
+        class="ml-auto"
+  >{{ view.label }}</time>
+  <span *ngIf="view.events.length === 0" class="sr-only">0 évènement</span>
+  <ng-template [ngIf]="view.events.length > 0">
+    <span class="sr-only">{{ view.events.length }} évènements</span>
+    <span class="-mx-0.5 mt-auto flex flex-wrap-reverse">
+      <span *ngFor="let event of view.events" 
+            class="mx-0.5 mb-1 h-1.5 w-1.5 rounded-full bg-gray-400 dark:bg-gray-300"
+      ></span>
+    </span>
+  </ng-template>
+</ng-template>
 <ng-template
   #monthViewDefaultEventDetailTemplate
   let-showEventDetail="showEventDetail"
@@ -75,6 +90,7 @@
     [eventSource]="eventSource"
     [markDisabled]="markDisabled"
     [monthViewDisplayEventTemplate]="monthViewDisplayEventTemplate || monthViewDefaultDisplayEventTemplate"
+    [monthViewDisplayResponsiveEventTemplate]="monthViewDisplayResponsiveEventTemplate || monthViewDefaultDisplayResponsiveEventTemplate"
     [monthViewEventDetailTemplate]="monthViewEventDetailTemplate|| monthViewDefaultEventDetailTemplate"
     [locale]="locale"
     [dateFormatter]="dateFormatter"
diff --git a/src/app/shared/components/calendar/calendar/calendar.component.ts b/src/app/shared/components/calendar/calendar/calendar.component.ts
index 8f3840c..1d9615a 100644
--- a/src/app/shared/components/calendar/calendar/calendar.component.ts
+++ b/src/app/shared/components/calendar/calendar/calendar.component.ts
@@ -75,6 +75,8 @@ export class CalendarComponent implements OnInit, OnDestroy {
   @Input()
   monthViewDisplayEventTemplate!: TemplateRef<IMonthViewDisplayEventTemplateContext>;
   @Input()
+  monthViewDisplayResponsiveEventTemplate!: TemplateRef<IMonthViewDisplayEventTemplateContext>;
+  @Input()
   monthViewEventDetailTemplate!: TemplateRef<IMonthViewEventDetailTemplateContext>;
   @Input() weekViewHeaderTemplate!: TemplateRef<IDisplayWeekViewHeader>;
   @Input() weekViewAllDayEventTemplate!: TemplateRef<IDisplayAllDayEvent>;
diff --git a/src/app/shared/components/calendar/month/month-view.component.html b/src/app/shared/components/calendar/month/month-view.component.html
index dd7d69c..fd4e7b9 100644
--- a/src/app/shared/components/calendar/month/month-view.component.html
+++ b/src/app/shared/components/calendar/month/month-view.component.html
@@ -13,213 +13,16 @@
     <div class="flex text-xs leading-6 bg-gray-200 text-slate-700 lg:flex-auto dark:bg-gray-600 dark:text-slate-300">
       <!-- Desktop View -->
       <div class="hidden w-full lg:grid lg:grid-cols-7 lg:grid-rows-6 lg:gap-px">
-        <div *ngFor="let view of view.dates" class="relative px-3 py-2" tappable [ngClass]="getHighlightClass(view)" (click)="select(view)">
+        <div *ngFor="let view of view.dates" class="relative px-3 py-2 hover:cursor-pointer" tappable [ngClass]="getHighlightClass(view)" (click)="select(view)">
           <ng-template [ngTemplateOutlet]="monthViewDisplayEventTemplate"
                         [ngTemplateOutletContext]="{ view }"></ng-template>
         </div>
       </div>
       <!-- Mobile View -->
       <div class="grid w-full grid-cols-7 grid-rows-6 gap-px isolate lg:hidden">
-        <!--
-          Always include: "flex h-14 flex-col py-2 px-3 hover:bg-gray-100 focus:z-10"
-          Is current month, include: "bg-white"
-          Is not current month, include: "bg-gray-50"
-          Is selected or is today, include: "font-semibold"
-          Is selected, include: "text-white"
-          Is not selected and is today, include: "text-primary-600"
-          Is not selected and is current month, and is not today, include: "text-gray-900"
-          Is not selected, is not current month, and is not today: "text-gray-500"
-        -->
-        <button type="button" class="flex flex-col px-3 py-2 text-gray-500 h-14 bg-gray-50 hover:bg-gray-100 focus:z-10">
-          <!--
-            Always include: "ml-auto"
-            Is selected, include: "flex h-6 w-6 items-center justify-center rounded-full"
-            Is selected and is today, include: "bg-primary-600"
-            Is selected and is not today, include: "bg-gray-900"
-          -->
-          <time datetime="2021-12-27" class="ml-auto">27</time>
-          <span class="sr-only">0 events</span>
-        </button>
-        <button type="button" class="flex flex-col px-3 py-2 text-gray-500 h-14 bg-gray-50 hover:bg-gray-100 focus:z-10">
-          <time datetime="2021-12-28" class="ml-auto">28</time>
-          <span class="sr-only">0 events</span>
-        </button>
-        <button type="button" class="flex flex-col px-3 py-2 text-gray-500 h-14 bg-gray-50 hover:bg-gray-100 focus:z-10">
-          <time datetime="2021-12-29" class="ml-auto">29</time>
-          <span class="sr-only">0 events</span>
-        </button>
-        <button type="button" class="flex flex-col px-3 py-2 text-gray-500 h-14 bg-gray-50 hover:bg-gray-100 focus:z-10">
-          <time datetime="2021-12-30" class="ml-auto">30</time>
-          <span class="sr-only">0 events</span>
-        </button>
-        <button type="button" class="flex flex-col px-3 py-2 text-gray-500 h-14 bg-gray-50 hover:bg-gray-100 focus:z-10">
-          <time datetime="2021-12-31" class="ml-auto">31</time>
-          <span class="sr-only">0 events</span>
-        </button>
-        <button type="button" class="flex flex-col px-3 py-2 text-gray-900 bg-white h-14 hover:bg-gray-100 focus:z-10">
-          <time datetime="2022-01-01" class="ml-auto">1</time>
-          <span class="sr-only">0 events</span>
-        </button>
-        <button type="button" class="flex flex-col px-3 py-2 text-gray-900 bg-white h-14 hover:bg-gray-100 focus:z-10">
-          <time datetime="2022-01-02" class="ml-auto">2</time>
-          <span class="sr-only">0 events</span>
-        </button>
-        <button type="button" class="flex flex-col px-3 py-2 text-gray-900 bg-white h-14 hover:bg-gray-100 focus:z-10">
-          <time datetime="2022-01-03" class="ml-auto">3</time>
-          <span class="sr-only">2 events</span>
-          <span class="-mx-0.5 mt-auto flex flex-wrap-reverse">
-            <span class="mx-0.5 mb-1 h-1.5 w-1.5 rounded-full bg-gray-400"></span>
-            <span class="mx-0.5 mb-1 h-1.5 w-1.5 rounded-full bg-gray-400"></span>
-          </span>
-        </button>
-        <button type="button" class="flex flex-col px-3 py-2 text-gray-900 bg-white h-14 hover:bg-gray-100 focus:z-10">
-          <time datetime="2022-01-04" class="ml-auto">4</time>
-          <span class="sr-only">0 events</span>
-        </button>
-        <button type="button" class="flex flex-col px-3 py-2 text-gray-900 bg-white h-14 hover:bg-gray-100 focus:z-10">
-          <time datetime="2022-01-05" class="ml-auto">5</time>
-          <span class="sr-only">0 events</span>
-        </button>
-        <button type="button" class="flex flex-col px-3 py-2 text-gray-900 bg-white h-14 hover:bg-gray-100 focus:z-10">
-          <time datetime="2022-01-06" class="ml-auto">6</time>
-          <span class="sr-only">0 events</span>
-        </button>
-        <button type="button" class="flex flex-col px-3 py-2 text-gray-900 bg-white h-14 hover:bg-gray-100 focus:z-10">
-          <time datetime="2022-01-07" class="ml-auto">7</time>
-          <span class="sr-only">1 event</span>
-          <span class="-mx-0.5 mt-auto flex flex-wrap-reverse">
-            <span class="mx-0.5 mb-1 h-1.5 w-1.5 rounded-full bg-gray-400"></span>
-          </span>
-        </button>
-        <button type="button" class="flex flex-col px-3 py-2 text-gray-900 bg-white h-14 hover:bg-gray-100 focus:z-10">
-          <time datetime="2022-01-08" class="ml-auto">8</time>
-          <span class="sr-only">0 events</span>
-        </button>
-        <button type="button" class="flex flex-col px-3 py-2 text-gray-900 bg-white h-14 hover:bg-gray-100 focus:z-10">
-          <time datetime="2022-01-09" class="ml-auto">9</time>
-          <span class="sr-only">0 events</span>
-        </button>
-        <button type="button" class="flex flex-col px-3 py-2 text-gray-900 bg-white h-14 hover:bg-gray-100 focus:z-10">
-          <time datetime="2022-01-10" class="ml-auto">10</time>
-          <span class="sr-only">0 events</span>
-        </button>
-        <button type="button" class="flex flex-col px-3 py-2 text-gray-900 bg-white h-14 hover:bg-gray-100 focus:z-10">
-          <time datetime="2022-01-11" class="ml-auto">11</time>
-          <span class="sr-only">0 events</span>
-        </button>
-        <button type="button" class="flex flex-col px-3 py-2 font-semibold bg-white text-primary-600 h-14 hover:bg-gray-100 focus:z-10">
-          <time datetime="2022-01-12" class="ml-auto">12</time>
-          <span class="sr-only">1 event</span>
-          <span class="-mx-0.5 mt-auto flex flex-wrap-reverse">
-            <span class="mx-0.5 mb-1 h-1.5 w-1.5 rounded-full bg-gray-400"></span>
-          </span>
-        </button>
-        <button type="button" class="flex flex-col px-3 py-2 text-gray-900 bg-white h-14 hover:bg-gray-100 focus:z-10">
-          <time datetime="2022-01-13" class="ml-auto">13</time>
-          <span class="sr-only">0 events</span>
-        </button>
-        <button type="button" class="flex flex-col px-3 py-2 text-gray-900 bg-white h-14 hover:bg-gray-100 focus:z-10">
-          <time datetime="2022-01-14" class="ml-auto">14</time>
-          <span class="sr-only">0 events</span>
-        </button>
-        <button type="button" class="flex flex-col px-3 py-2 text-gray-900 bg-white h-14 hover:bg-gray-100 focus:z-10">
-          <time datetime="2022-01-15" class="ml-auto">15</time>
-          <span class="sr-only">0 events</span>
-        </button>
-        <button type="button" class="flex flex-col px-3 py-2 text-gray-900 bg-white h-14 hover:bg-gray-100 focus:z-10">
-          <time datetime="2022-01-16" class="ml-auto">16</time>
-          <span class="sr-only">0 events</span>
-        </button>
-        <button type="button" class="flex flex-col px-3 py-2 text-gray-900 bg-white h-14 hover:bg-gray-100 focus:z-10">
-          <time datetime="2022-01-17" class="ml-auto">17</time>
-          <span class="sr-only">0 events</span>
-        </button>
-        <button type="button" class="flex flex-col px-3 py-2 text-gray-900 bg-white h-14 hover:bg-gray-100 focus:z-10">
-          <time datetime="2022-01-18" class="ml-auto">18</time>
-          <span class="sr-only">0 events</span>
-        </button>
-        <button type="button" class="flex flex-col px-3 py-2 text-gray-900 bg-white h-14 hover:bg-gray-100 focus:z-10">
-          <time datetime="2022-01-19" class="ml-auto">19</time>
-          <span class="sr-only">0 events</span>
-        </button>
-        <button type="button" class="flex flex-col px-3 py-2 text-gray-900 bg-white h-14 hover:bg-gray-100 focus:z-10">
-          <time datetime="2022-01-20" class="ml-auto">20</time>
-          <span class="sr-only">0 events</span>
-        </button>
-        <button type="button" class="flex flex-col px-3 py-2 text-gray-900 bg-white h-14 hover:bg-gray-100 focus:z-10">
-          <time datetime="2022-01-21" class="ml-auto">21</time>
-          <span class="sr-only">0 events</span>
-        </button>
-        <button type="button" class="flex flex-col px-3 py-2 font-semibold text-white bg-white h-14 hover:bg-gray-100 focus:z-10">
-          <time datetime="2022-01-22" class="flex items-center justify-center w-6 h-6 ml-auto bg-gray-900 rounded-full">22</time>
-          <span class="sr-only">2 events</span>
-          <span class="-mx-0.5 mt-auto flex flex-wrap-reverse">
-            <span class="mx-0.5 mb-1 h-1.5 w-1.5 rounded-full bg-gray-400"></span>
-            <span class="mx-0.5 mb-1 h-1.5 w-1.5 rounded-full bg-gray-400"></span>
-          </span>
-        </button>
-        <button type="button" class="flex flex-col px-3 py-2 text-gray-900 bg-white h-14 hover:bg-gray-100 focus:z-10">
-          <time datetime="2022-01-23" class="ml-auto">23</time>
-          <span class="sr-only">0 events</span>
-        </button>
-        <button type="button" class="flex flex-col px-3 py-2 text-gray-900 bg-white h-14 hover:bg-gray-100 focus:z-10">
-          <time datetime="2022-01-24" class="ml-auto">24</time>
-          <span class="sr-only">0 events</span>
-        </button>
-        <button type="button" class="flex flex-col px-3 py-2 text-gray-900 bg-white h-14 hover:bg-gray-100 focus:z-10">
-          <time datetime="2022-01-25" class="ml-auto">25</time>
-          <span class="sr-only">0 events</span>
-        </button>
-        <button type="button" class="flex flex-col px-3 py-2 text-gray-900 bg-white h-14 hover:bg-gray-100 focus:z-10">
-          <time datetime="2022-01-26" class="ml-auto">26</time>
-          <span class="sr-only">0 events</span>
-        </button>
-        <button type="button" class="flex flex-col px-3 py-2 text-gray-900 bg-white h-14 hover:bg-gray-100 focus:z-10">
-          <time datetime="2022-01-27" class="ml-auto">27</time>
-          <span class="sr-only">0 events</span>
-        </button>
-        <button type="button" class="flex flex-col px-3 py-2 text-gray-900 bg-white h-14 hover:bg-gray-100 focus:z-10">
-          <time datetime="2022-01-28" class="ml-auto">28</time>
-          <span class="sr-only">0 events</span>
-        </button>
-        <button type="button" class="flex flex-col px-3 py-2 text-gray-900 bg-white h-14 hover:bg-gray-100 focus:z-10">
-          <time datetime="2022-01-29" class="ml-auto">29</time>
-          <span class="sr-only">0 events</span>
-        </button>
-        <button type="button" class="flex flex-col px-3 py-2 text-gray-900 bg-white h-14 hover:bg-gray-100 focus:z-10">
-          <time datetime="2022-01-30" class="ml-auto">30</time>
-          <span class="sr-only">0 events</span>
-        </button>
-        <button type="button" class="flex flex-col px-3 py-2 text-gray-900 bg-white h-14 hover:bg-gray-100 focus:z-10">
-          <time datetime="2022-01-31" class="ml-auto">31</time>
-          <span class="sr-only">0 events</span>
-        </button>
-        <button type="button" class="flex flex-col px-3 py-2 text-gray-500 h-14 bg-gray-50 hover:bg-gray-100 focus:z-10">
-          <time datetime="2022-02-01" class="ml-auto">1</time>
-          <span class="sr-only">0 events</span>
-        </button>
-        <button type="button" class="flex flex-col px-3 py-2 text-gray-500 h-14 bg-gray-50 hover:bg-gray-100 focus:z-10">
-          <time datetime="2022-02-02" class="ml-auto">2</time>
-          <span class="sr-only">0 events</span>
-        </button>
-        <button type="button" class="flex flex-col px-3 py-2 text-gray-500 h-14 bg-gray-50 hover:bg-gray-100 focus:z-10">
-          <time datetime="2022-02-03" class="ml-auto">3</time>
-          <span class="sr-only">0 events</span>
-        </button>
-        <button type="button" class="flex flex-col px-3 py-2 text-gray-500 h-14 bg-gray-50 hover:bg-gray-100 focus:z-10">
-          <time datetime="2022-02-04" class="ml-auto">4</time>
-          <span class="sr-only">1 event</span>
-          <span class="-mx-0.5 mt-auto flex flex-wrap-reverse">
-            <span class="mx-0.5 mb-1 h-1.5 w-1.5 rounded-full bg-gray-400"></span>
-          </span>
-        </button>
-        <button type="button" class="flex flex-col px-3 py-2 text-gray-500 h-14 bg-gray-50 hover:bg-gray-100 focus:z-10">
-          <time datetime="2022-02-05" class="ml-auto">5</time>
-          <span class="sr-only">0 events</span>
-        </button>
-        <button type="button" class="flex flex-col px-3 py-2 text-gray-500 h-14 bg-gray-50 hover:bg-gray-100 focus:z-10">
-          <time datetime="2022-02-06" class="ml-auto">6</time>
-          <span class="sr-only">0 events</span>
+        <button *ngFor="let view of view.dates" type="button" class="flex flex-col px-3 py-2 text-slate-500 dark:text-slate-400 h-14 bg-gray-50 hover:bg-gray-100 focus:z-10" tappable [ngClass]="getHighlightClass(view)" (click)="select(view)">
+          <ng-template [ngTemplateOutlet]="monthViewDisplayResponsiveEventTemplate"
+                        [ngTemplateOutletContext]="{ view }"></ng-template>
         </button>
       </div>
     </div>
diff --git a/src/app/shared/components/calendar/month/month-view.component.ts b/src/app/shared/components/calendar/month/month-view.component.ts
index 1c4aa7e..401bfcc 100644
--- a/src/app/shared/components/calendar/month/month-view.component.ts
+++ b/src/app/shared/components/calendar/month/month-view.component.ts
@@ -34,6 +34,8 @@ export class MonthViewComponent
   @Input()
   monthViewDisplayEventTemplate!: TemplateRef<IMonthViewDisplayEventTemplateContext>;
   @Input()
+  monthViewDisplayResponsiveEventTemplate!: TemplateRef<IMonthViewDisplayEventTemplateContext>;
+  @Input()
   monthViewInactiveDisplayEventTemplate!: TemplateRef<IMonthViewDisplayEventTemplateContext>;
   @Input()
   monthViewEventDetailTemplate!:
