[A] user.service, edit username in profile

This commit is contained in:
Jan 2020-10-30 14:42:44 +01:00
parent ccde75f72a
commit ef07db5818
7 changed files with 249 additions and 12 deletions

View file

@ -1,7 +1,8 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { createClient, SupabaseAuthUser, SupabaseClient } from '@supabase/supabase-js' import { createClient, SupabaseAuthUser, SupabaseClient } from '@supabase/supabase-js'
import { BehaviorSubject } from 'rxjs'; import { Subject } from 'rxjs';
import { environment } from '../../../environments/environment' import { environment } from '../../../environments/environment'
import { User } from './user';
@Injectable({ @Injectable({
@ -9,7 +10,9 @@ import { environment } from '../../../environments/environment'
}) })
export class SupaService { export class SupaService {
client: SupabaseClient; client: SupabaseClient;
user: BehaviorSubject<SupabaseAuthUser> = new BehaviorSubject(null); user: Subject<SupabaseAuthUser> = new Subject();
supabaseUser: SupabaseAuthUser;
userProfile: User;
constructor() { constructor() {
// Create a single supabase client for interacting with your database // Create a single supabase client for interacting with your database
@ -20,9 +23,39 @@ export class SupaService {
async getUser() { async getUser() {
const user = await this.client.auth.user(); const user = await this.client.auth.user();
console.log('user', user); console.log('user', user);
this.supabaseUser = user;
this.getUserProfile();
this.user.next(user); this.user.next(user);
} }
getUserProfile(user_id: string = this.supabaseUser.id) {
const subject: Subject<User> = new Subject();
if (!this.userProfile) {
this.client.from<User>('user').select().match({id: <never>user_id})
.then(data => {
console.log('getUserProfile', data)
if (data.body.length === 0) {
// create default user profile
this.client.from<User>('user').insert(new User(user_id, this.supabaseUser.email.split('@')[0]))
.then(data => {
console.log('created UserProfile', data.body[0]);
this.userProfile = data.body[0];
subject.next(this.userProfile);
})
.catch(error => console.error('Error creating UserProfile', error))
} else {
console.log('loaded UserProfile', data.body[0]);
this.userProfile = data.body[0];
subject.next(this.userProfile);
}
})
.catch(error => console.error('getUserProfile', error))
} else {
setTimeout(() =>subject.next(this.userProfile), 100);
}
return subject.asObservable();
}
async login(email: string, password: string): Promise<SupabaseAuthUser> { async login(email: string, password: string): Promise<SupabaseAuthUser> {
try { try {
const res = await this.client.auth.login( const res = await this.client.auth.login(

View file

@ -0,0 +1,16 @@
import { TestBed } from '@angular/core/testing';
import { UserService } from './user.service';
describe('UserService', () => {
let service: UserService;
beforeEach(() => {
TestBed.configureTestingModule({});
service = TestBed.inject(UserService);
});
it('should be created', () => {
expect(service).toBeTruthy();
});
});

View file

@ -0,0 +1,159 @@
import { Injectable } from '@angular/core';
import { BehaviorSubject, Observable, of, Subject } from 'rxjs';
import { map } from 'rxjs/internal/operators/map';
import { SupaService } from './supa.service';
import { User } from './user';
@Injectable({
providedIn: 'root'
})
export class UserService {
userMap = {};
users: BehaviorSubject<User[]> = new BehaviorSubject(Object.values(this.userMap));
isListening: boolean = true;
constructor(
private supa: SupaService,
) { }
/**
* Get Users from local store.
* Requests data if store is emtpy.
* @returns Observable<User[]>
*/
getStories(): Observable<User[]> {
if (Object.values(this.userMap).length === 0) {
this.subscribeToUsers();
console.log('getUsers- REFRESH')
this.supa.client.from<User>('user').select()
.then(data => {
this.updateStore(data.body);
})
.catch(error => {
console.error(error);
});
}
return this.users.asObservable();
}
/**
* Listen to realtime events from users db.
*/
subscribeToUsers() {
if (!this.isListening) {
this.isListening = true;
this.supa.client.from<User>('user').on('*', payload => {
console.log('subscribeToStories - REALTIME EVENT', payload)
if ((payload.eventType === 'INSERT') || (payload.eventType === 'UPDATE')) {
this.userMap[payload.new.id] = payload.new;
} else {
delete this.userMap[payload.old.id];
}
this.next();
}).subscribe();
}
}
/**
* Update the local store with provided users
* @param users
*/
updateStore(users: User[]) {
users.forEach(e => {
// this.userMap.set(e.id, e);
this.userMap[e.id] = e;
});
console.log('update users', this.userMap)
this.next();
}
/**
* Emits local store.
*/
next = () => {
console.log('next', Object.values(this.userMap))
this.users.next(Object.values(this.userMap))
};
/**
* Retrieve users from local store.
* @param id
*/
getOne(id: number) {
if (this.userMap[id]) {
return of(this.userMap[id]);
} else {
const subject: Subject<User> = new Subject();
this.supa.client.from<User>('user').select('id, name, description')
.filter(<never>'id', 'eq', id)
.then(data => {
this.updateStore([data.body[0]]);
subject.next(data.body[0]);
subject.complete();
})
.catch(error => {
subject.error(error);
subject.complete();
});
return subject.asObservable();
}
}
/**
* Update a users data.
* @param users
*/
updateOne(user: User): Observable<User> {
const subject: Subject<User> = new Subject();
this.supa.client.from<User>('user').update(user)
.match({ id: user.id })
.then(data => {
subject.next(data.body[0]);
subject.complete();
})
.catch(error => {
subject.error(error);
subject.complete();
});
return subject.asObservable();
}
/**
* Removes one user from db.
* @param user
*/
deleteOne(user: User): Observable<User> {
const subject: Subject<User> = new Subject();
this.supa.client.from<User>('user').delete()
.match({ id: user.id })
.then(data => {
subject.next(user);
subject.complete();
})
.catch(error => {
subject.error(error);
subject.complete();
});
return subject.asObservable();
}
/**
* Creates a user on the db.
* @param users
*/
addOne(user: User): Observable<User> {
const subject: Subject<User> = new Subject();
this.supa.client.from<User>('user').insert(user)
.then(data => {
subject.next(data.body[0]);
subject.complete();
})
.catch(error => {
subject.error(error);
subject.complete();
});
return subject.asObservable();
}
}

View file

@ -0,0 +1,11 @@
export class User {
id: string;
status: 'OFFLINE' |'ONLINE';
username: string;
constructor(id: string, username: string, status: 'OFFLINE' | 'ONLINE' = 'ONLINE') {
this.id = id;
this.username = username;
this.status = status;
}
}

View file

@ -8,6 +8,7 @@ import { FormsModule } from '@angular/forms';
import { SupaService } from './api/supabase/supa.service'; import { SupaService } from './api/supabase/supa.service';
import { StandupService } from './api/supabase/standup.service'; import { StandupService } from './api/supabase/standup.service';
import { StoryService } from './api/supabase/story.service'; import { StoryService } from './api/supabase/story.service';
import { UserService } from './api/supabase/user.service';
import { AuthGuard } from './authguard.service'; import { AuthGuard } from './authguard.service';
import { AppComponent } from "./app.component"; import { AppComponent } from "./app.component";
@ -42,6 +43,7 @@ import { DashboardComponent } from './dashboard/dashboard.component';
SupaService, SupaService,
StandupService, StandupService,
StoryService, StoryService,
UserService,
AuthGuard, AuthGuard,
], ],
bootstrap: [ bootstrap: [

View file

@ -1,6 +1,12 @@
<div class="row">
<div class="col-12 col-sm-3">
<legend>Profile</legend> <legend>Profile</legend>
<pre> <form *ngIf="user">
<code *ngIf="user"> <div class="form-group">
{{ user | json }} <label for="username">Username</label>
</code> <input type="text" class="form-control" name="username" aria-describedby="Input for username." [(ngModel)]="user.username">
</pre> </div>
<button type="submit" class="btn btn-primary" (submit)="updateUser()" (click)="updateUser()">Save</button>
</form>
</div>
</div>

View file

@ -1,6 +1,8 @@
import { Component, OnInit } from '@angular/core'; import { Component, OnInit } from '@angular/core';
import { SupabaseAuthUser } from '@supabase/supabase-js'; import { SupabaseAuthUser } from '@supabase/supabase-js';
import { SupaService } from '../api/supabase/supa.service'; import { SupaService } from '../api/supabase/supa.service';
import { User } from '../api/supabase/user';
import { UserService } from '../api/supabase/user.service';
@Component({ @Component({
selector: 'app-profile', selector: 'app-profile',
@ -8,17 +10,25 @@ import { SupaService } from '../api/supabase/supa.service';
styleUrls: ['./profile.component.scss'] styleUrls: ['./profile.component.scss']
}) })
export class ProfileComponent implements OnInit { export class ProfileComponent implements OnInit {
user: SupabaseAuthUser; user: User;
constructor( constructor(
public supa: SupaService, private supaService: SupaService,
private userService: UserService,
) { } ) { }
ngOnInit(): void { ngOnInit(): void {
this.supa.client.auth.user().then(user => { this.supaService.getUserProfile().subscribe((user:User) => {
console.log('user', user) console.log('user', user);
this.user = user; this.user = user;
}); });
} }
updateUser() {
this.userService.updateOne(this.user).subscribe(
data => console.log('Success', data),
error => console.error(error)
)
}
} }