Skip to content

Commit

Permalink
checkpoint: demo
Browse files Browse the repository at this point in the history
  • Loading branch information
dereekb committed Apr 25, 2022
1 parent 1885463 commit b0f87e0
Show file tree
Hide file tree
Showing 61 changed files with 662 additions and 34 deletions.
1 change: 1 addition & 0 deletions apps/demo-api/src/app/function/auth/auth.function.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export const initUserOnCreate = onEventWithDemoNestContext<UserRecord>((withNest
functions.auth.user().onCreate(withNest(async (nest, data: UserRecord, context) => {
const uid = data.uid;

console.log('Init user: ', uid, context);

if (uid) {
await nest.profileActions.initProfileForUid(uid);
Expand Down
7 changes: 6 additions & 1 deletion apps/demo-firebase/src/lib/collection.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
import { FirestoreContext } from '@dereekb/firebase';
import { guestbookEntryFirestoreCollectionFactory, GuestbookEntryFirestoreCollectionFactory, guestbookFirestoreCollection, GuestbookFirestoreCollection, GuestbookFirestoreCollections } from './guestbook';
import { profileFirestoreCollection, ProfileFirestoreCollection, ProfileFirestoreCollections, profilePrivateDataFirestoreCollectionFactory, ProfilePrivateDataFirestoreCollectionFactory } from './profile/profile';

export abstract class DemoFirestoreCollections implements ProfileFirestoreCollections {
export abstract class DemoFirestoreCollections implements ProfileFirestoreCollections, GuestbookFirestoreCollections {
abstract readonly guestbookFirestoreCollection: GuestbookFirestoreCollection;
abstract readonly guestbookEntryCollectionFactory: GuestbookEntryFirestoreCollectionFactory;
abstract readonly profileFirestoreCollection: ProfileFirestoreCollection;
abstract readonly profilePrivateDataCollectionFactory: ProfilePrivateDataFirestoreCollectionFactory;
}

export function makeDemoFirestoreCollections(firestoreContext: FirestoreContext): DemoFirestoreCollections {
return {
guestbookFirestoreCollection: guestbookFirestoreCollection(firestoreContext),
guestbookEntryCollectionFactory: guestbookEntryFirestoreCollectionFactory(firestoreContext),
profileFirestoreCollection: profileFirestoreCollection(firestoreContext),
profilePrivateDataCollectionFactory: profilePrivateDataFirestoreCollectionFactory(firestoreContext)
};
Expand Down
5 changes: 5 additions & 0 deletions apps/demo-firebase/src/lib/guestbook/guestbook.query.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { FirestoreQueryConstraint, where } from "@dereekb/firebase";

export function guestbookEntryWithUsername(username: string): FirestoreQueryConstraint {
return where('username', '==', username);
}
121 changes: 121 additions & 0 deletions apps/demo-firebase/src/lib/guestbook/guestbook.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
import { CollectionReference, AbstractFirestoreDocument, makeSnapshotConverterFunctions, firestoreString, firestoreDate, FirestoreCollection, UserRelatedById, DocumentReferenceRef, FirestoreContext, FirestoreCollectionWithParent, firestoreBoolean } from "@dereekb/firebase";

export interface GuestbookFirestoreCollections {
guestbookFirestoreCollection: GuestbookFirestoreCollection;
guestbookEntryCollectionFactory: GuestbookEntryFirestoreCollectionFactory;
}

// MARK: Guestbook
export interface Guestbook {
/**
* Whether or not this guestbook should show up in the list.
*
* If not active, this item is still considered locked.
*/
active: boolean;
/**
* Guestbook name
*/
name: string;
/**
* Whether or not this guestbook and it's entries can still be edited.
*/
locked: boolean;
/**
* Last date the guestbook was updated at.
*/
lockedAt: Date;
}

export interface GuestbookRef extends DocumentReferenceRef<Guestbook> { }

export class GuestbookDocument extends AbstractFirestoreDocument<Guestbook, GuestbookDocument> { }

export const guestbookCollectionPath = 'guestbook';

export const guestbookConverter = makeSnapshotConverterFunctions<Guestbook>({
fields: {
active: firestoreBoolean(),
name: firestoreString(),
locked: firestoreBoolean(),
lockedAt: firestoreDate()
}
});

export function guestbookCollectionReference(context: FirestoreContext): CollectionReference<Guestbook> {
return context.collection(guestbookCollectionPath).withConverter<Guestbook>(guestbookConverter);
}

export type GuestbookFirestoreCollection = FirestoreCollection<Guestbook, GuestbookDocument>;

export function guestbookFirestoreCollection(firestoreContext: FirestoreContext): GuestbookFirestoreCollection {
return firestoreContext.firestoreCollection({
itemsPerPage: 50,
collection: guestbookCollectionReference(firestoreContext),
makeDocument: (accessor, documentAccessor) => new GuestbookDocument(accessor, documentAccessor),
firestoreContext
});
}

// MARK: Guestbook Entry
export interface GuestbookEntry extends UserRelatedById {
/**
* Arbitrary word without spaces
*/
word: string;
/**
* Guestbook message.
*/
message: string;
/**
* Arbitrary string for signature
*/
signed: string;
/**
* Date the entry was last updated at.
*/
updatedAt: Date;
/**
* Date the entry was originally created at.
*/
createdAt: Date;
}

export interface GuestbookEntryRef extends DocumentReferenceRef<GuestbookEntry> { }

export class GuestbookEntryDocument extends AbstractFirestoreDocument<GuestbookEntry, GuestbookEntryDocument> { }

export const guestbookEntryCollectionPath = 'guestbookEntry';

export const guestbookEntryConverter = makeSnapshotConverterFunctions<GuestbookEntry>({
fields: {
word: firestoreString(),
message: firestoreString(),
signed: firestoreString(),
updatedAt: firestoreDate(),
createdAt: firestoreDate({ saveDefaultAsNow: true })
}
});

export function guestbookEntryCollectionReferenceFactory(context: FirestoreContext): (guestbook: GuestbookDocument) => CollectionReference<GuestbookEntry> {
return (guestbook: GuestbookDocument) => {
return context.subcollection(guestbook.documentRef, guestbookEntryCollectionPath).withConverter<GuestbookEntry>(guestbookEntryConverter);
};
}

export type GuestbookEntryFirestoreCollection = FirestoreCollectionWithParent<GuestbookEntry, Guestbook, GuestbookEntryDocument>;
export type GuestbookEntryFirestoreCollectionFactory = (parent: GuestbookDocument) => GuestbookEntryFirestoreCollection;

export function guestbookEntryFirestoreCollectionFactory(firestoreContext: FirestoreContext): GuestbookEntryFirestoreCollectionFactory {
const factory = guestbookEntryCollectionReferenceFactory(firestoreContext);

return (parent: GuestbookDocument) => {
return firestoreContext.firestoreCollectionWithParent({
itemsPerPage: 50,
collection: factory(parent),
makeDocument: (accessor, documentAccessor) => new GuestbookEntryDocument(accessor, documentAccessor),
firestoreContext,
parent
});
}
}
2 changes: 2 additions & 0 deletions apps/demo-firebase/src/lib/guestbook/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './guestbook';
export * from './guestbook.query';
1 change: 1 addition & 0 deletions apps/demo-firebase/src/lib/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export * from './guestbook';
export * from './profile';
export * from './collection';
2 changes: 1 addition & 1 deletion apps/demo-firebase/src/lib/profile/profile.api.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Profile } from './profile';
import { Expose } from "class-transformer";
import { FirebaseFunctionMap, FirebaseFunctionMapFactory, firebaseFunctionMapFactory, FirebaseFunctionMapFunction, FirebaseFunctionTypeConfigMap } from "@dereekb/firebase";
import { FirebaseFunctionMap, firebaseFunctionMapFactory, FirebaseFunctionTypeConfigMap } from "@dereekb/firebase";
import { IsNotEmpty, IsOptional, IsString, MaxLength } from "class-validator";

export class SetProfileUsernameParams {
Expand Down
4 changes: 4 additions & 0 deletions apps/demo/src/app/container/layout.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@
<button mat-button>Demo</button>
</dbx-anchor>
<span class="spacer"></span>
<dbx-anchor [anchor]="emulator">
<button mat-flat-button color="accent">Emulator Enabled</button>
</dbx-anchor>
<span class="spacer"></span>
<dbx-anchor [anchor]="toggleDarkTheme">
<button mat-button>Toggle Dark Theme</button>
</dbx-anchor>
Expand Down
14 changes: 14 additions & 0 deletions apps/demo/src/app/container/layout.component.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { DbxStyleService } from '@dereekb/dbx-web';
import { ClickableAnchor } from '@dereekb/dbx-core';
import { Component } from '@angular/core';
import { environment } from '../../environments/environment';

@Component({
templateUrl: './layout.component.html',
Expand Down Expand Up @@ -31,4 +32,17 @@ export class AppLayoutComponent {

constructor(readonly dbxStyleService: DbxStyleService) { }

get showEmulatorButton() {
return (environment.firebase.emulators.useEmulators === true);
}

get emulator(): ClickableAnchor {
const ui = environment.firebase.emulators?.ui;

return (ui) ? {
url: `http://${ui.host ?? 'localhost'}:${ui.port}`,
target: '_blank'
} : {};
}

}
5 changes: 4 additions & 1 deletion apps/demo/src/app/modules/demo/container/home.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,11 @@
<dbx-content-container>
<dbx-content-box>
<h2>Demo App</h2>
<p>This is the public view of the demo app.</p>
<p>This is the public view of the demo app. Anyone can see this page whether or not they are logged in.</p>
<p>You can login or go to the app <dbx-link ref="demo.app">here</dbx-link>.</p>
<dbx-anchor ref="demo.app">
<button mat-button>Go to App</button>
</dbx-anchor>
</dbx-content-box>
</dbx-content-container>
</dbx-content-page>
16 changes: 12 additions & 4 deletions apps/demo/src/app/modules/demo/container/layout.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,21 +12,29 @@ import { DbxFirebaseAuthService } from '@dereekb/dbx-firebase';
export class DemoLayoutComponent {

readonly everyoneAnchors = [{
title: 'Home',
title: 'Public Home',
ref: 'demo.home',
icon: 'home'
}];

readonly adminAnchors = [{
title: 'Home',
title: 'Admin Home',
ref: 'demo.home',
icon: 'home'
}];

readonly userAnchors = [{
title: 'Home',
ref: 'demo.home',
title: 'App Home',
ref: 'demo.app.home',
icon: 'home'
}, {
title: 'Guest Book',
ref: 'demo.app.guestbook.list',
icon: 'list'
}, {
title: 'Your Profile',
ref: 'demo.app.profile',
icon: 'person'
}];

readonly navAnchors$: Observable<ClickableAnchorLinkSegueRef[]> = of({
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<ui-view></ui-view>
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { Component } from '@angular/core';

@Component({
templateUrl: './layout.component.html'
})
export class DemoGuestbookLayoutComponent {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<dbx-two-column>
<dbx-two-block left>
<dbx-two-column-head top></dbx-two-column-head>
<demo-guestbook-list></demo-guestbook-list>
</dbx-two-block>
<ui-view right></ui-view>
</dbx-two-column>
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { Component } from '@angular/core';

@Component({
templateUrl: './list.component.html'
})
export class DemoGuestbookListPageComponent {

constructor() { }

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<dbx-two-column-right header="Guestbook">
<dbx-content-container>
<p>View Guest Book</p>
</dbx-content-container>
</dbx-two-column-right>
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { Component } from '@angular/core';

@Component({
templateUrl: './list.right.component.html'
})
export class DemoGuestbookListPageRightComponent {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { NgModule } from '@angular/core';
import { UIRouterModule } from '@uirouter/angular';
import { STATES } from './guestbook.router';
import { DemoAppSharedModule } from '../../../shared/demo.app.shared.module';
import { DemoGuestbookListPageRightComponent } from './container/list.right.component';
import { DemoGuestbookListPageComponent } from './container/list.component';
import { DemoGuestbookLayoutComponent } from './container/layout.component';

@NgModule({
imports: [
DemoAppSharedModule,
UIRouterModule.forChild({
states: STATES
})
],
declarations: [
DemoGuestbookLayoutComponent,
DemoGuestbookListPageComponent,
DemoGuestbookListPageRightComponent
],
})
export class DemoGuestbookModule { }
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { Ng2StateDeclaration } from '@uirouter/angular';
import { DemoGuestbookLayoutComponent } from './container/layout.component';
import { DemoGuestbookListPageComponent } from './container/list.component';
import { DemoGuestbookListPageRightComponent } from './container/list.right.component';

export const layoutState: Ng2StateDeclaration = {
url: '/guestbook',
name: 'demo.app.guestbook',
redirectTo: 'demo.app.guestbook.list',
component: DemoGuestbookLayoutComponent
};

export const guestbookListState: Ng2StateDeclaration = {
name: 'demo.app.guestbook.list',
component: DemoGuestbookListPageComponent
};

export const guestbookListRightState: Ng2StateDeclaration = {
url: '/:id',
name: 'demo.app.guestbook.list.guestbook',
component: DemoGuestbookListPageRightComponent
};

export const STATES: Ng2StateDeclaration[] = [
layoutState,
guestbookListState
];
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<dbx-content-container>
<ui-view></ui-view>
</dbx-content-container>
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { Component } from '@angular/core';

@Component({
templateUrl: './layout.component.html'
})
export class DemoProfileLayoutComponent {}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<p>Profile</p>
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { Component } from '@angular/core';

@Component({
templateUrl: './profile.component.html'
})
export class DemoProfileViewComponent {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { DemoProfileViewComponent } from './container/profile.component';
import { DemoProfileLayoutComponent } from './container/layout.component';
import { NgModule } from '@angular/core';
import { UIRouterModule } from '@uirouter/angular';
import { STATES } from './profile.router';
import { AppSharedModule } from '@/shared/app.shared.module';

@NgModule({
imports: [
AppSharedModule,
UIRouterModule.forChild({
states: STATES
})
],
declarations: [
DemoProfileLayoutComponent,
DemoProfileViewComponent
],
})
export class DemoProfileModule { }
Loading

0 comments on commit b0f87e0

Please sign in to comment.