[A] profile, channe-list, channel, dashboard, standup.service
This commit is contained in:
parent
a5531c5cdf
commit
e1aa1342c2
27 changed files with 393 additions and 18 deletions
16
src/app/api/supabase/standup.service.spec.ts
Normal file
16
src/app/api/supabase/standup.service.spec.ts
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
import { TestBed } from '@angular/core/testing';
|
||||
|
||||
import { StandupService } from './standup.service';
|
||||
|
||||
describe('StandupService', () => {
|
||||
let service: StandupService;
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({});
|
||||
service = TestBed.inject(StandupService);
|
||||
});
|
||||
|
||||
it('should be created', () => {
|
||||
expect(service).toBeTruthy();
|
||||
});
|
||||
});
|
||||
55
src/app/api/supabase/standup.service.ts
Normal file
55
src/app/api/supabase/standup.service.ts
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
import { Injectable } from '@angular/core';
|
||||
import { BehaviorSubject, Observable } from 'rxjs';
|
||||
import { StandUp } from './standup';
|
||||
import { SupaService } from './supa.service';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class StandupService {
|
||||
// standupMap: Map<number, StandUp> = new Map();
|
||||
standupMap = {};
|
||||
standups: BehaviorSubject<any> = new BehaviorSubject([]);
|
||||
|
||||
constructor(
|
||||
private supa: SupaService,
|
||||
) { }
|
||||
|
||||
getStandUps(): Observable<StandUp[]> {
|
||||
if (Object.values(this.standupMap).length === 0) {
|
||||
console.log('getStandUps - REFRESH')
|
||||
return this.refreshStandUps();
|
||||
} else {
|
||||
console.log('getStandUps - LOCAL')
|
||||
return this.standups.asObservable();
|
||||
}
|
||||
}
|
||||
|
||||
refreshStandUps(): Observable<StandUp[]> {
|
||||
this.supa.client.from<StandUp>('standup').select('id, name, description')
|
||||
.then(standups => this.updateStore(standups.body))
|
||||
.catch(error => console.log('Error: ', error));
|
||||
return this.standups.asObservable();
|
||||
}
|
||||
|
||||
updateStore(standups: StandUp[]) {
|
||||
standups.forEach(e => {
|
||||
// this.standupMap.set(e.id, e);
|
||||
this.standupMap[e.id] = e;
|
||||
});
|
||||
this.standups.next(Object.values(this.standupMap));
|
||||
}
|
||||
|
||||
updateOne(standup: StandUp) {
|
||||
|
||||
}
|
||||
|
||||
deleteOne(standup: StandUp) {
|
||||
|
||||
}
|
||||
|
||||
addOne(standup: StandUp) {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
5
src/app/api/supabase/standup.ts
Normal file
5
src/app/api/supabase/standup.ts
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
export class StandUp {
|
||||
id: number;
|
||||
name: string;
|
||||
description: string;
|
||||
}
|
||||
|
|
@ -6,12 +6,29 @@ import { HuddleComponent } from './huddle/huddle.component';
|
|||
import { LoginComponent } from './login/login.component';
|
||||
import { SignupComponent } from './signup/signup.component';
|
||||
import { AuthGuard } from './authguard.service';
|
||||
import { ProfileComponent } from './profile/profile.component';
|
||||
import { DashboardComponent } from './dashboard/dashboard.component';
|
||||
import { ChannelComponent } from './channel/channel.component';
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
||||
path: 'huddle',
|
||||
path: 'huddle/:id',
|
||||
component: HuddleComponent,
|
||||
canActivate: [AuthGuard]
|
||||
},{
|
||||
path: 'channel/:id',
|
||||
component: ChannelComponent,
|
||||
canActivate: [AuthGuard]
|
||||
},
|
||||
{
|
||||
path: 'profile',
|
||||
component: ProfileComponent,
|
||||
canActivate: [AuthGuard]
|
||||
},
|
||||
{
|
||||
path: 'home',
|
||||
component: DashboardComponent,
|
||||
canActivate: [AuthGuard]
|
||||
},
|
||||
{
|
||||
path: 'login',
|
||||
|
|
@ -21,7 +38,7 @@ const routes: Routes = [
|
|||
path: 'signup',
|
||||
component: SignupComponent,
|
||||
},
|
||||
{ path: '**', redirectTo: '/huddle', pathMatch: 'full' },
|
||||
{ path: '**', redirectTo: '/home', pathMatch: 'full' },
|
||||
]
|
||||
|
||||
@NgModule({
|
||||
|
|
|
|||
|
|
@ -1,7 +1,14 @@
|
|||
<nav class="navbar navbar-light bg-light">
|
||||
<nav class="navbar navbar-dark bg-dark">
|
||||
<a class="navbar-brand" href="#" style="margin: 0 auto;">ASYNC HUDDLE</a>
|
||||
<span *ngIf="supa.user | async" (click)="logout()">Logout</span>
|
||||
<span *ngIf="supa.user | async" (click)="logout()" class="cursor-pointer">Logout</span>
|
||||
</nav>
|
||||
<div class="container">
|
||||
<div class="container-fluid p-0">
|
||||
<div class="myContainer d-flex">
|
||||
<div class="menu">
|
||||
<app-channel-list></app-channel-list>
|
||||
</div>
|
||||
<div class="container content">
|
||||
<router-outlet></router-outlet>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,24 @@
|
|||
.cursor-pointer {
|
||||
cursor: pointer;
|
||||
font-weight: 500;
|
||||
color: white;
|
||||
&:hover {
|
||||
color: lightseagreen;
|
||||
}
|
||||
}
|
||||
|
||||
.container-fluid {
|
||||
height: calc(100% - 56px);
|
||||
}
|
||||
|
||||
.container.content {
|
||||
padding-top: 15px;
|
||||
height: 100%;
|
||||
max-width: 100%;
|
||||
// overflow-x: scroll;
|
||||
}
|
||||
|
||||
.myContainer {
|
||||
min-height: 100%;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
|
@ -6,6 +6,7 @@ import { AppRoutingModule } from './app-routing.module';
|
|||
import { FormsModule } from '@angular/forms';
|
||||
|
||||
import { SupaService } from './api/supabase/supa.service';
|
||||
import { StandupService } from './api/supabase/standup.service';
|
||||
import { AuthGuard } from './authguard.service';
|
||||
|
||||
import { AppComponent } from "./app.component";
|
||||
|
|
@ -13,6 +14,10 @@ import { RecorderComponent } from './recorder/recorder.component';
|
|||
import { LoginComponent } from './login/login.component';
|
||||
import { SignupComponent } from './signup/signup.component';
|
||||
import { HuddleComponent } from './huddle/huddle.component';
|
||||
import { ProfileComponent } from './profile/profile.component';
|
||||
import { ChannelComponent } from './channel/channel.component';
|
||||
import { ChannelListComponent } from './channel-list/channel-list.component';
|
||||
import { DashboardComponent } from './dashboard/dashboard.component';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
|
|
@ -20,7 +25,11 @@ import { HuddleComponent } from './huddle/huddle.component';
|
|||
RecorderComponent,
|
||||
HuddleComponent,
|
||||
LoginComponent,
|
||||
SignupComponent
|
||||
SignupComponent,
|
||||
ProfileComponent,
|
||||
ChannelComponent,
|
||||
ChannelListComponent,
|
||||
DashboardComponent
|
||||
],
|
||||
imports: [
|
||||
BrowserModule,
|
||||
|
|
@ -30,6 +39,7 @@ import { HuddleComponent } from './huddle/huddle.component';
|
|||
],
|
||||
providers: [
|
||||
SupaService,
|
||||
StandupService,
|
||||
AuthGuard,
|
||||
],
|
||||
bootstrap: [
|
||||
|
|
|
|||
17
src/app/channel-list/channel-list.component.html
Normal file
17
src/app/channel-list/channel-list.component.html
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
<div class="list bg-dark text-white p-3">
|
||||
<p><strong>Standup</strong> <strong class="newBtn">+</strong></p>
|
||||
<ul class="list-unstyled">
|
||||
<li *ngFor="let s of standups" [title]="s.description" [routerLink]="'/huddle/'+s.id">{{s.name}}</li>
|
||||
</ul>
|
||||
<p><strong>Channel</strong> <strong class="newBtn">+</strong></p>
|
||||
<ul class="list-unstyled">
|
||||
<li>...</li>
|
||||
<li>...</li>
|
||||
<li>...</li>
|
||||
<li>...</li>
|
||||
</ul>
|
||||
<p><strong>Settings</strong></p>
|
||||
<ul class="list-unstyled">
|
||||
<li [routerLink]="'/profile'">Profile</li>
|
||||
</ul>
|
||||
</div>
|
||||
22
src/app/channel-list/channel-list.component.scss
Normal file
22
src/app/channel-list/channel-list.component.scss
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
.list {
|
||||
height: 100%;
|
||||
max-width: 300px;
|
||||
border-top: 1px dashed lightgray;
|
||||
li {
|
||||
padding: 5px 10px;
|
||||
border-radius: 5px;
|
||||
&:hover {
|
||||
color: lightseagreen;
|
||||
// -webkit-box-shadow: inset 0px 0px 4px 4px rgba(211, 211, 211, 0.4);
|
||||
// box-shadow: inset 0px 0px 4px 4px rgba(211, 211, 211, 0.4);
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
.newBtn {
|
||||
margin-left:5px;
|
||||
&:hover {
|
||||
cursor: pointer;
|
||||
color: lightseagreen;
|
||||
}
|
||||
}
|
||||
}
|
||||
25
src/app/channel-list/channel-list.component.spec.ts
Normal file
25
src/app/channel-list/channel-list.component.spec.ts
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { ChannelListComponent } from './channel-list.component';
|
||||
|
||||
describe('ChannelListComponent', () => {
|
||||
let component: ChannelListComponent;
|
||||
let fixture: ComponentFixture<ChannelListComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ ChannelListComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(ChannelListComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
29
src/app/channel-list/channel-list.component.ts
Normal file
29
src/app/channel-list/channel-list.component.ts
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
import { Component, OnInit } from '@angular/core';
|
||||
import { Observable, throwError } from 'rxjs';
|
||||
import { StandUp } from '../api/supabase/standup';
|
||||
import { StandupService } from '../api/supabase/standup.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-channel-list',
|
||||
templateUrl: './channel-list.component.html',
|
||||
styleUrls: ['./channel-list.component.scss']
|
||||
})
|
||||
export class ChannelListComponent implements OnInit {
|
||||
standups: StandUp[] = [];
|
||||
|
||||
constructor(
|
||||
private standupSevice: StandupService,
|
||||
) { }
|
||||
|
||||
ngOnInit() {
|
||||
this.loadStandUps().subscribe(standups => {
|
||||
console.log('ChannelListComponent - StandUps', standups);
|
||||
this.standups = standups;
|
||||
});
|
||||
}
|
||||
|
||||
loadStandUps(): Observable<StandUp[]> {
|
||||
return this.standupSevice.getStandUps();
|
||||
}
|
||||
|
||||
}
|
||||
1
src/app/channel/channel.component.html
Normal file
1
src/app/channel/channel.component.html
Normal file
|
|
@ -0,0 +1 @@
|
|||
<p>channel works!</p>
|
||||
0
src/app/channel/channel.component.scss
Normal file
0
src/app/channel/channel.component.scss
Normal file
25
src/app/channel/channel.component.spec.ts
Normal file
25
src/app/channel/channel.component.spec.ts
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { ChannelComponent } from './channel.component';
|
||||
|
||||
describe('ChannelComponent', () => {
|
||||
let component: ChannelComponent;
|
||||
let fixture: ComponentFixture<ChannelComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ ChannelComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(ChannelComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
15
src/app/channel/channel.component.ts
Normal file
15
src/app/channel/channel.component.ts
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
import { Component, OnInit } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-channel',
|
||||
templateUrl: './channel.component.html',
|
||||
styleUrls: ['./channel.component.scss']
|
||||
})
|
||||
export class ChannelComponent implements OnInit {
|
||||
|
||||
constructor() { }
|
||||
|
||||
ngOnInit(): void {
|
||||
}
|
||||
|
||||
}
|
||||
1
src/app/dashboard/dashboard.component.html
Normal file
1
src/app/dashboard/dashboard.component.html
Normal file
|
|
@ -0,0 +1 @@
|
|||
<p>dashboard works!</p>
|
||||
0
src/app/dashboard/dashboard.component.scss
Normal file
0
src/app/dashboard/dashboard.component.scss
Normal file
25
src/app/dashboard/dashboard.component.spec.ts
Normal file
25
src/app/dashboard/dashboard.component.spec.ts
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { DashboardComponent } from './dashboard.component';
|
||||
|
||||
describe('DashboardComponent', () => {
|
||||
let component: DashboardComponent;
|
||||
let fixture: ComponentFixture<DashboardComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ DashboardComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(DashboardComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
15
src/app/dashboard/dashboard.component.ts
Normal file
15
src/app/dashboard/dashboard.component.ts
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
import { Component, OnInit } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-dashboard',
|
||||
templateUrl: './dashboard.component.html',
|
||||
styleUrls: ['./dashboard.component.scss']
|
||||
})
|
||||
export class DashboardComponent implements OnInit {
|
||||
|
||||
constructor() { }
|
||||
|
||||
ngOnInit(): void {
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
import { Component, OnInit, ViewChild } from "@angular/core";
|
||||
import { NgbModal, NgbModalRef } from "@ng-bootstrap/ng-bootstrap";
|
||||
import { SupaService } from '../api/supabase/supa.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-huddle',
|
||||
|
|
@ -33,10 +34,12 @@ export class HuddleComponent implements OnInit {
|
|||
];
|
||||
selectedUser;
|
||||
|
||||
constructor(private modalService: NgbModal) {}
|
||||
constructor(
|
||||
private modalService: NgbModal,
|
||||
public supa: SupaService,
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
|
||||
}
|
||||
|
||||
playStory(user) {
|
||||
|
|
|
|||
6
src/app/profile/profile.component.html
Normal file
6
src/app/profile/profile.component.html
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
<legend>Profile</legend>
|
||||
<pre>
|
||||
<code *ngIf="user">
|
||||
{{ user | json }}
|
||||
</code>
|
||||
</pre>
|
||||
0
src/app/profile/profile.component.scss
Normal file
0
src/app/profile/profile.component.scss
Normal file
25
src/app/profile/profile.component.spec.ts
Normal file
25
src/app/profile/profile.component.spec.ts
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { ProfileComponent } from './profile.component';
|
||||
|
||||
describe('ProfileComponent', () => {
|
||||
let component: ProfileComponent;
|
||||
let fixture: ComponentFixture<ProfileComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ ProfileComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(ProfileComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
24
src/app/profile/profile.component.ts
Normal file
24
src/app/profile/profile.component.ts
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
import { Component, OnInit } from '@angular/core';
|
||||
import { SupabaseAuthUser } from '@supabase/supabase-js';
|
||||
import { SupaService } from '../api/supabase/supa.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-profile',
|
||||
templateUrl: './profile.component.html',
|
||||
styleUrls: ['./profile.component.scss']
|
||||
})
|
||||
export class ProfileComponent implements OnInit {
|
||||
user: SupabaseAuthUser;
|
||||
|
||||
constructor(
|
||||
public supa: SupaService,
|
||||
) { }
|
||||
|
||||
ngOnInit(): void {
|
||||
this.supa.client.auth.user().then(user => {
|
||||
console.log('user', user)
|
||||
this.user = user;
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -2,9 +2,9 @@
|
|||
|
||||
|
||||
<ng-template #content let-modal>
|
||||
<div class="modal-body d-flex flex-column">
|
||||
<div>
|
||||
<span class="float-right" (click)="modal.dismiss('Cross click')">
|
||||
<div class="modal-header">
|
||||
<strong>Record a stoy</strong>
|
||||
<span class="float-right cursor-pointer" (click)="modal.dismiss('Cross click')">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M6.2253 4.81108C5.83477 4.42056 5.20161 4.42056 4.81108 4.81108C4.42056 5.20161 4.42056 5.83477 4.81108 6.2253L10.5858 12L4.81114 17.7747C4.42062 18.1652 4.42062 18.7984 4.81114 19.1889C5.20167 19.5794 5.83483 19.5794 6.22535 19.1889L12 13.4142L17.7747 19.1889C18.1652 19.5794 18.7984 19.5794 19.1889 19.1889C19.5794 18.7984 19.5794 18.1652 19.1889 17.7747L13.4142 12L19.189 6.2253C19.5795 5.83477 19.5795 5.20161 19.189 4.81108C18.7985 4.42056 18.1653 4.42056 17.7748 4.81108L12 10.5858L6.2253 4.81108Z"
|
||||
|
|
@ -12,6 +12,7 @@
|
|||
</svg>
|
||||
</span>
|
||||
</div>
|
||||
<div class="modal-body d-flex flex-column">
|
||||
<video *ngIf="stream" [id]="id" [srcObject]="stream" class="video-recorder" autoplay muted volume="0"></video>
|
||||
<button *ngIf="!isRecording" class="btn btn-success" (click)="startRecording()">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
|
|
|
|||
|
|
@ -2,3 +2,9 @@
|
|||
max-height: 50vh;
|
||||
max-width: 90vw;
|
||||
}
|
||||
.cursor-pointer {
|
||||
cursor: pointer;
|
||||
&:hover {
|
||||
color: lightseagreen;
|
||||
}
|
||||
}
|
||||
|
|
@ -3,4 +3,5 @@
|
|||
html,
|
||||
body {
|
||||
font-family: sans-serif;
|
||||
height: 100%;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue