Skip to content

Commit d5cb8ad

Browse files
committed
initial commit
1 parent 0f8e76a commit d5cb8ad

40 files changed

+168171
-25
lines changed

angular.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
"tsConfig": "tsconfig.app.json",
2323
"assets": [
2424
"src/favicon.ico",
25-
"src/assets",
25+
"src/assets",
2626
{
2727
"glob": "**/*",
2828
"input": "public"

src/app/app.component.css

+45
Original file line numberDiff line numberDiff line change
@@ -37,4 +37,49 @@ main {
3737
font-size: 1.5rem;
3838
text-align: left;
3939
}
40+
}
41+
42+
menu {
43+
width: 90%;
44+
margin: 2.5rem auto;
45+
max-width: 50rem;
46+
padding: 0;
47+
}
48+
49+
menu button {
50+
font: inherit;
51+
cursor: pointer;
52+
background-color: #9965dd;
53+
border-radius: 4px;
54+
border: none;
55+
padding: 0.35rem 0.8rem;
56+
margin: 0 0.25rem;
57+
font-size: 0.9rem;
58+
}
59+
60+
61+
menu button:hover,
62+
menu button:active {
63+
background-color: #a565dd
64+
}
65+
66+
ul {
67+
list-style: none;
68+
margin: 1rem 0;
69+
padding: 0;
70+
display: flex;
71+
flex-direction: column;
72+
gap: 1rem;
73+
max-height: 50vh;
74+
overflow: auto;
75+
}
76+
77+
@media (min-width: 768px) {
78+
h2 {
79+
font-size: 1.25rem;
80+
}
81+
82+
menu {
83+
width: auto;
84+
}
4085
}

src/app/app.component.html

+29-15
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,29 @@
1-
<app-header></app-header>
2-
<main>
3-
<ul id="users">
4-
@for(user of users; track user.id){
5-
<li>
6-
<app-user [user]="user" (select)="onSelectUser($event)" [selected]="user.id === selectedUserId"></app-user>
7-
</li>
8-
}
9-
</ul>
10-
@if (selectedUser){
11-
<app-tasks [userId]="selectedUser.id" [userName]="selectedUser.name"></app-tasks>
12-
} @else {
13-
<p id="fallback">please select a user to see the details.</p>
14-
}
15-
</main>
1+
<div>
2+
@if(showLayout){
3+
<app-header>
4+
</app-header>
5+
<header>
6+
<menu>
7+
<button (click)="onAddTask()">Redirect to Wellness</button>
8+
<button (click)="onAddFeature()">Redirect to Feature</button>
9+
</menu>
10+
</header>
11+
<main>
12+
<ul id="users">
13+
@for(user of users; track user.id){
14+
<li>
15+
<app-user [user]="user" (select)="onSelectUser($event)" [selected]="user.id === selectedUserId"></app-user>
16+
</li>
17+
}
18+
</ul>
19+
@if (selectedUser){
20+
<app-tasks [userId]="selectedUser.id" [userName]="selectedUser.name"></app-tasks>
21+
} @else {
22+
<p id="fallback">please select a user to see the details.</p>
23+
}
24+
</main>
25+
}
26+
@else{
27+
<router-outlet></router-outlet>
28+
}
29+
</div>

src/app/app.component.ts

+35-5
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,53 @@
11
import { Component, signal } from '@angular/core';
22
import { RouterOutlet } from '@angular/router';
3+
import { Router, NavigationEnd, RouterModule } from '@angular/router'; // Import RouterModule and NavigationEnd
34
import { HeaderComponent } from './header/header.component';
4-
import { UserComponent } from "./user/user.component";
5+
import { UserComponent } from './user/user.component';
56
import { DUMMY_USERS } from './dummy-users';
6-
import { TasksComponent } from "./tasks/tasks.component";
7+
import { TasksComponent } from './tasks/tasks.component';
8+
import { Subscription } from 'rxjs';
9+
10+
import { WellnessComponent } from './wellness/wellness.component';
711

812
@Component({
913
selector: 'app-root',
1014
standalone: true,
11-
imports: [RouterOutlet, HeaderComponent, UserComponent, TasksComponent],
15+
imports: [HeaderComponent, UserComponent, TasksComponent, RouterOutlet],
1216
templateUrl: './app.component.html',
1317
styleUrl: './app.component.css',
1418
})
1519
export class AppComponent {
20+
onAddFeature() {
21+
//throw new Error('Method not implemented.');
22+
}
23+
24+
showLayout: boolean = true; // Flag to determine whether to show header and main
25+
26+
private routerSubscription!: Subscription;
27+
28+
constructor(private router: Router) {}
29+
30+
ngOnInit(): void {
31+
this.routerSubscription = this.router.events.subscribe((event) => {
32+
if (event instanceof NavigationEnd) {
33+
// Check if the current URL starts with '/wellness'
34+
this.showLayout = !event.urlAfterRedirects.startsWith('/wellness');
35+
}
36+
});
37+
}
38+
39+
ngOnDestroy(): void {
40+
this.routerSubscription.unsubscribe();
41+
}
42+
43+
onAddTask() {
44+
this.router.navigate(['/wellness']);
45+
}
1646

17-
selectedUserId? : String ;
47+
selectedUserId?: String;
1848

1949
get selectedUser() {
20-
return this.users.find(user => user.id === this.selectedUserId);
50+
return this.users.find((user) => user.id === this.selectedUserId);
2151
}
2252

2353
onSelectUser(id: string) {

src/app/app.routes.ts

+6-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
// src/app/app.routes.ts
12
import { Routes } from '@angular/router';
3+
import { WellnessComponent } from './wellness/wellness.component'; // Adjust the path as necessary
24

3-
export const routes: Routes = [];
5+
export const routes: Routes = [
6+
{ path: 'wellness', component: WellnessComponent },
7+
// You can add more routes here if needed
8+
];

src/app/header/header.component.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<header>
22
<img src="assets/task-management-logo.png" alt="TODo list"/>
3-
<h1>Nas Header</h1>
3+
<h1> Header</h1>
44
<p>Enterprise level task management</p>
55
</header>
+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#flutter-container {
2+
width: 100%;
3+
height: 600px; /* Adjust as needed */
4+
}
5+
host div {
6+
width: 100%;
7+
height: 600px;
8+
position: relative;
9+
}
10+
.spinner {
11+
position: absolute;
12+
top: 50%;
13+
left: 50%;
14+
transform: translate(-50%, -50%);
15+
}
+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<!-- src/app/wellness/wellness.component.html -->
2+
<div #flutterTarget style="width: 100%; height: 600px; position: relative;">
3+
<div class="spinner">
4+
Loading Wellness App...
5+
</div>
6+
</div>
7+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { ComponentFixture, TestBed } from '@angular/core/testing';
2+
3+
import { WellnessComponent } from './wellness.component';
4+
5+
describe('WellnessComponent', () => {
6+
let component: WellnessComponent;
7+
let fixture: ComponentFixture<WellnessComponent>;
8+
9+
beforeEach(async () => {
10+
await TestBed.configureTestingModule({
11+
imports: [WellnessComponent]
12+
})
13+
.compileComponents();
14+
15+
fixture = TestBed.createComponent(WellnessComponent);
16+
component = fixture.componentInstance;
17+
fixture.detectChanges();
18+
});
19+
20+
it('should create', () => {
21+
expect(component).toBeTruthy();
22+
});
23+
});
+95
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
import { Component, AfterViewInit, ViewChild, ElementRef, Output, EventEmitter } from '@angular/core';
2+
3+
// Declare the global _flutter namespace
4+
declare var _flutter: any;
5+
6+
@Component({
7+
selector: 'app-wellness',
8+
standalone: true,
9+
templateUrl: './wellness.component.html',
10+
styles: [`
11+
:host div {
12+
width: 100%;
13+
height: 600px;
14+
position: relative;
15+
}
16+
.spinner {
17+
position: absolute;
18+
top: 50%;
19+
left: 50%;
20+
transform: translate(-50%, -50%);
21+
}
22+
`],
23+
})
24+
export class WellnessComponent implements AfterViewInit {
25+
@ViewChild('flutterTarget', { static: true }) flutterTarget!: ElementRef;
26+
27+
@Output() appLoaded: EventEmitter<Object> = new EventEmitter<Object>();
28+
29+
private src: string = 'assets/flutter/main.dart.js'; // Adjust path as needed
30+
private assetBase: string = 'assets/flutter/'; // Adjust path as needed
31+
32+
// Hardcoded initial data
33+
private initialData: any = {
34+
accessToken: 'eyJraWQiOiJuSmNFMDFrVkFjMG1RMzBDSTVJMnRPUUorTmExbVRqc3FmWE1WSW9QdU9rPSIsImFsZyI6IlJTMjU2In0.eyJzdWIiOiIxOTRiMmQzYS04ZDdlLTQzMzgtOTEwMS0zYjY0MmVjNDZkMTMiLCJldmVudF9pZCI6ImY1NzY1MmZjLTdlZDYtNDEzYy05MTk1LTdiZDU3YzY3NjI3YSIsInRva2VuX3VzZSI6ImFjY2VzcyIsInNjb3BlIjoiYXdzLmNvZ25pdG8uc2lnbmluLnVzZXIuYWRtaW4iLCJhdXRoX3RpbWUiOjE3MzEzOTk5NzgsImlzcyI6Imh0dHBzOlwvXC9jb2duaXRvLWlkcC5jYS1jZW50cmFsLTEuYW1hem9uYXdzLmNvbVwvY2EtY2VudHJhbC0xX2Z5dm9Bb25LTiIsImV4cCI6MTczMTQ4NjQwMiwiaWF0IjoxNzMxNDAwMDAyLCJqdGkiOiIzNjE1NjE5NS0yMzVhLTRhYzktOWQ3OC1iZGFiYTAyYzA1MDYiLCJjbGllbnRfaWQiOiIyb29vNDkzZHBuNWNzN3J1aW80bG1wNDcyaSIsInVzZXJuYW1lIjoiMTk0YjJkM2EtOGQ3ZS00MzM4LTkxMDEtM2I2NDJlYzQ2ZDEzIn0.paUzWsHh87ThaKeadtDy4yL_Q8k84S5IOngbZf6zuh-3Ez4Pknt-ThhUWoL9Lhy7VhUnlNUSk31_bGMp4JRFKzbqQEooxYFanRMJesNqsruBk0G1N-Kia-cG6LQDs2lXx39D6aOSiJ9_bzzOqS0Phj5uiyU8LayIpgpjdAL0CnlS2CikjM6OFhGkY_0RgU-x1-jRniqy3Zk3Gii1W3DRWEDfPovxNqVnjPrL6kQpGuQBMfr6E_xupNFAfdgw6PtgEm_RYO61N8WBaZqK3XNXT36YlJQvgn5-vWhvdqD5keTCj7FYXdElcpjP6zB1uI4zQD41Sc8H0TlA7rmx261wjQ',
35+
identityToken: 'eyJraWQiOiJIOUIxcUw2aDFwbjJnQjVoNWF3amV1a0ZOOURZMHdHYXhZaVB5Uk80bGg0PSIsImFsZyI6IlJTMjU2In0.eyJpY2FuX2VuYWJsZWQiOiJmYWxzZSIsInN1YiI6IjE5NGIyZDNhLThkN2UtNDMzOC05MTAxLTNiNjQyZWM0NmQxMyIsInVzZXJfY2xhaW1zIjoiW3tcInN5c3RlbVwiOlwiYWxheWFjYXJlXCIsXCJhdXRob3JpemVkSWRzXCI6W1wiNDYxNlwiLFwiNDY5NlwiXX1dIiwiZW1haWxfdmVyaWZpZWQiOnRydWUsImNpdHVzIjoie30iLCJpc3MiOiJodHRwczpcL1wvY29nbml0by1pZHAuY2EtY2VudHJhbC0xLmFtYXpvbmF3cy5jb21cL2NhLWNlbnRyYWwtMV9meXZvQW9uS04iLCJwaG9uZV9udW1iZXJfdmVyaWZpZWQiOnRydWUsImNvZ25pdG86dXNlcm5hbWUiOiIxOTRiMmQzYS04ZDdlLTQzMzgtOTEwMS0zYjY0MmVjNDZkMTMiLCJ1c2VyX2NsYWltc192MiI6Ilt7XCJwc0lkXCI6XCI4OTcxNjYwMDA0XCIsXCJzeXN0ZW1UeXBlXCI6XCJob21lQ2FyZVwiLFwiYXV0aG9yaXplZFN5c3RlbXNcIjpbe1wiaWRcIjpcIjQ2MTZcIixcIm5hbWVcIjpcImFsYXlhY2FyZVwiLFwidXNlclR5cGVcIjpcImNsaWVudFwiLFwidGVuYW50c1wiOltcIkRlZmF1bHRcIl19XX0se1wicHNJZFwiOlwiODk3MTY2MDAxNFwiLFwic3lzdGVtVHlwZVwiOlwiaG9tZUNhcmVcIixcImF1dGhvcml6ZWRTeXN0ZW1zXCI6W3tcImlkXCI6XCI0Njk2XCIsXCJuYW1lXCI6XCJhbGF5YWNhcmVcIixcInVzZXJUeXBlXCI6XCJjbGllbnRcIixcInRlbmFudHNcIjpbXCJEZWZhdWx0XCJdfV19XSIsImN1c3RvbTphY2NlcHRlZF9kaWdpX3Rlcm1zIjoiMSIsImdpdmVuX25hbWUiOiJtYWRkeSIsImN1c3RvbTphY2NlcHRlZF90ZXJtcyI6IjEiLCJhdWQiOiIyb29vNDkzZHBuNWNzN3J1aW80bG1wNDcyaSIsImV2ZW50X2lkIjoiZjU3NjUyZmMtN2VkNi00MTNjLTkxOTUtN2JkNTdjNjc2MjdhIiwidG9rZW5fdXNlIjoiaWQiLCJhdXRoX3RpbWUiOjE3MzEzOTk5NzgsInBob25lX251bWJlciI6IisxNTE5NzIyMzQxNiIsImN1c3RvbTpsYXN0X2xvZ2luIjoiMTczMTQwMDAwMSIsImV4cCI6MTczMTQ4NjQwMiwiaWF0IjoxNzMxNDAwMDAyLCJmYW1pbHlfbmFtZSI6ImdyZWVuIiwiY3VzdG9tOnByZWZlcnJlZF9sYW5ndWFnZSI6ImVuIiwiZW1haWwiOiJncmVlbjIxQG1haWxpbmF0b3IuY29tIn0.qP7bD3L_N4saU2NneVlkRS6xFoUYHB_KEBawBE0VKEXMThyDl4vBt0411EP_nJmYJ-q-Ndrx54eY6FppUaiARUZhnp8qe_aR96OwYPzo5uyx2ultkkp0Esj4PYBEyGQAnLG5VfuSxHTEmjbifZe_96-6_Pf1yu8pJVv-HYCm3gg2t2iNG9xGhFSXyjnJLW2fPbQnnhtagxUxzBDYMGPgljNculbeidRIrT1-RWI33qznlJ8PN6jK3rAZ9dlswbgQ4cSqltHfDK0e2oUW6gqrUampvN_wLHiYLe8n8csclvJw3gIsvgK3M8WXGbpuwZzueTqRCysznBHyO7Zciwz4Ng',
36+
systemId: '8971660004',
37+
env: 'dev',
38+
};
39+
40+
ngAfterViewInit(): void {
41+
const target: HTMLElement = this.flutterTarget.nativeElement;
42+
console.log('Initializing Flutter app in target:', target);
43+
44+
// Define the initial data in a global JS variable
45+
window.flutterInitialData = JSON.stringify(this.initialData);
46+
47+
// Dynamically load flutter.js if not already loaded
48+
if (typeof _flutter === 'undefined') {
49+
console.log('flutter.js not loaded. Loading...');
50+
const script = document.createElement('script');
51+
script.src = `${this.assetBase}flutter.js`;
52+
script.defer = true;
53+
script.onload = () => this.initializeFlutterApp(target);
54+
script.onerror = () => console.error('Failed to load flutter.js.');
55+
document.body.appendChild(script);
56+
} else {
57+
console.log('flutter.js already loaded.');
58+
this.initializeFlutterApp(target);
59+
}
60+
}
61+
62+
private initializeFlutterApp(target: HTMLElement) {
63+
console.log('Loading Flutter entrypoint:', this.src);
64+
65+
_flutter.loader.loadEntrypoint({
66+
entrypointUrl: this.src,
67+
onEntrypointLoaded: async (engineInitializer: any) => {
68+
console.log('Entrypoint loaded. Initializing engine...');
69+
let appRunner = await engineInitializer.initializeEngine({
70+
hostElement: target,
71+
assetBase: this.assetBase,
72+
// multiViewEnabled: true, // Uncomment if using multi-view
73+
});
74+
console.log('Engine initialized. Running app...');
75+
await appRunner.runApp();
76+
}
77+
});
78+
79+
target.addEventListener("flutter-initialized", (event: Event) => {
80+
let state = (event as CustomEvent).detail;
81+
window._debug = state;
82+
console.log('Flutter app has loaded:', state);
83+
this.appLoaded.emit(state);
84+
}, {
85+
once: true,
86+
});
87+
}
88+
89+
ngOnDestroy(): void {
90+
//window.removeEventListener('flutter-button-pressed', this.flutterButtonPressedHandler);
91+
if (_flutter && _flutter.engine) {
92+
_flutter.engine.destroy();
93+
}
94+
}
95+
}

src/assets/favicon.ico

-14.7 KB
Binary file not shown.

src/assets/flutter/assets/AssetManifest.bin

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
 packages/mbc_common/lang/en.json asset packages/mbc_common/lang/en.json packages/mbc_common/lang/fr.json asset packages/mbc_common/lang/fr.jsonweb/index.html assetweb/index.html
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
"DQMHIHBhY2thZ2VzL21iY19jb21tb24vbGFuZy9lbi5qc29uDAENAQcFYXNzZXQHIHBhY2thZ2VzL21iY19jb21tb24vbGFuZy9lbi5qc29uByBwYWNrYWdlcy9tYmNfY29tbW9uL2xhbmcvZnIuanNvbgwBDQEHBWFzc2V0ByBwYWNrYWdlcy9tYmNfY29tbW9uL2xhbmcvZnIuanNvbgcOd2ViL2luZGV4Lmh0bWwMAQ0BBwVhc3NldAcOd2ViL2luZGV4Lmh0bWw="
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"packages/mbc_common/lang/en.json":["packages/mbc_common/lang/en.json"],"packages/mbc_common/lang/fr.json":["packages/mbc_common/lang/fr.json"],"web/index.html":["web/index.html"]}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
[{"family":"MaterialIcons","fonts":[{"asset":"fonts/MaterialIcons-Regular.otf"}]}]

0 commit comments

Comments
 (0)