Skip to content

Commit

Permalink
Add project detail component
Browse files Browse the repository at this point in the history
  • Loading branch information
sondreb committed Oct 4, 2023
1 parent 29eff54 commit a5846f9
Show file tree
Hide file tree
Showing 10 changed files with 296 additions and 26 deletions.
20 changes: 18 additions & 2 deletions app/src/app/app-routing.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import { BadgeComponent } from './badge/badge';
import { ExampleComponent } from './example/example';
import { ProjectsComponent } from './projects/projects.component';
import { FilesComponent } from './files/files';
import { ProjectComponent } from './projects/project/project.component';

const routes: Routes = [
{
Expand Down Expand Up @@ -110,6 +111,14 @@ const routes: Routes = [
data: LoadingResolverService,
},
},
{
path: 'projects/:id',
component: ProjectComponent,
canActivate: [AuthGuard],
resolve: {
data: LoadingResolverService,
},
},
{
path: 'notifications',
component: NotificationsComponent,
Expand Down Expand Up @@ -264,7 +273,8 @@ const routes: Routes = [
},
{
path: 'about',
loadChildren: () => import('./about/about.module').then((m) => m.AboutModule),
loadChildren: () =>
import('./about/about.module').then((m) => m.AboutModule),
// component: AboutComponent,
// canActivate: [AuthGuard],
// resolve: {
Expand Down Expand Up @@ -326,7 +336,13 @@ const routes: Routes = [
];

@NgModule({
imports: [RouterModule.forRoot(routes, { scrollOffset: [0, 0], scrollPositionRestoration: 'enabled', anchorScrolling: 'enabled' })],
imports: [
RouterModule.forRoot(routes, {
scrollOffset: [0, 0],
scrollPositionRestoration: 'enabled',
anchorScrolling: 'enabled',
}),
],
exports: [RouterModule],
})
export class AppRoutingModule {}
2 changes: 1 addition & 1 deletion app/src/app/app.html
Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,7 @@
[routerLink]="['/projects']"
mat-menu-item
(click)="toggleMenu()"
[routerLinkActiveOptions]="{ exact: true }"
[routerLinkActiveOptions]="{ exact: false }"
routerLinkActive="active-nav-link"
>
<mat-icon>location_city</mat-icon>
Expand Down
4 changes: 3 additions & 1 deletion app/src/app/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,7 @@ import { ZappersListDialogComponent } from './shared/zappers-list-dialog/zappers
import { ExampleComponent } from './example/example';
import { ProjectsComponent } from './projects/projects.component';
import { FilesComponent } from './files/files';
import { ProjectComponent } from './projects/project/project.component';
@NgModule({
declarations: [
AppComponent,
Expand Down Expand Up @@ -249,7 +250,8 @@ import { FilesComponent } from './files/files';
ZappersListDialogComponent,
ExampleComponent,
ProjectsComponent,
FilesComponent
FilesComponent,
ProjectComponent
],
imports: [
HttpClientModule,
Expand Down
11 changes: 11 additions & 0 deletions app/src/app/legacy/services/api.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,17 @@ export class ApiService {
return result;
}

async project(id: string) {
const response = await fetch(`${environment.apiUrl}/project/${id}`);

if (response.status >= 400) {
throw new Error(response.statusText);
}

const result = await response.json();
return result;
}

async users() {
const response = await fetch(`${environment.apiUrl}/user`);

Expand Down
64 changes: 64 additions & 0 deletions app/src/app/projects/project/project.component.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
.loading {
margin: auto;
}

.input-full-width {
width: 100% !important;
}

.search {
margin-top: 1em;
padding: 1em 1em 0em 1em;
margin-bottom: 1em;
border-radius: 10px;
}

.circle-button {
}

.circle-button-icon {
}

.circle-container {
/* display: flex;
flex-direction: row;
flex-wrap: nowrap;
justify-content: center;
align-content: center;
align-items: center;
column-gap: 1em; */

margin-top: 1em;
padding: 1em;
margin-bottom: 1em;
border-radius: 10px;
}

.circle-item:nth-child(1) {
order: 0;
flex: 0 1 auto;
align-self: auto;
}

.circle-item:nth-child(2) {
order: 0;
flex: 1 1 auto;
align-self: auto;
}

.circle-item:nth-child(3) {
order: 0;
flex: 0 1 auto;
align-self: auto;
}

.circle-actions button {
margin-right: 0.4em;
margin-bottom: 0.4em;
}


.project-logo {
max-height: 64px;
max-width: 64px;
}
24 changes: 24 additions & 0 deletions app/src/app/projects/project/project.component.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<div class="page">
<mat-card class="example-card" *ngIf="project">
<mat-card-header>
<img mat-card-avatar [src]="project.logo" class="project-logo" />
<mat-card-title>{{ project.name }}</mat-card-title>
<mat-card-subtitle>{{ project.slogan }}</mat-card-subtitle>
</mat-card-header>
<mat-card-content>
<p>
{{ project.about }}
</p>
</mat-card-content>
<mat-card-actions>
<a
*ngFor="let link of project.links"
mat-button
[href]="[link.url]"
target="_blank"
>
{{ link.type }}
</a>
</mat-card-actions>
</mat-card>
</div>
166 changes: 166 additions & 0 deletions app/src/app/projects/project/project.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
import { ChangeDetectorRef, Component, NgZone } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { ApplicationState } from '../../services/applicationstate';
import { Utilities } from '../../services/utilities';
import { DataValidation } from '../../services/data-validation';
import { Circle, NostrProfileDocument } from '../../services/interfaces';
import { ProfileService } from '../../services/profile';
import { CircleService } from '../../services/circle';
import { CircleDialog } from '../../shared/create-circle-dialog/create-circle-dialog';
import { MatDialog } from '@angular/material/dialog';
import { MatSnackBar } from '@angular/material/snack-bar';
import { AuthenticationService } from '../../services/authentication';
import { copyToClipboard } from '../../shared/utilities';
import { Subscription, tap } from 'rxjs';
import { DataService } from '../../services/data';
import { NavigationService } from '../../services/navigation';
import { ApiService } from '../../legacy/services/api.service';

@Component({
selector: 'app-project',
templateUrl: './project.component.html',
styleUrls: ['./project.component.css'],
})
export class ProjectComponent {
publicKey?: string | null;
loading = false;
searchTerm: any;

constructor(
public navigation: NavigationService,
public appState: ApplicationState,
public circleService: CircleService,
private profileService: ProfileService,
public dialog: MatDialog,
private validator: DataValidation,
private utilities: Utilities,
private authService: AuthenticationService,
private router: Router,
private dataService: DataService,
private snackBar: MatSnackBar,
private cd: ChangeDetectorRef,
private ngZone: NgZone,
private apiService: ApiService,
private activatedRoute: ActivatedRoute
) {}

ngOnDestroy() {
this.utilities.unsubscribe(this.subscriptions);
}

async deleteCircle(id: number) {
const pubKeys = this.getFollowingInCircle(id).map((f) => f.pubkey);

await this.circleService.delete(id);

for (var i = 0; i < pubKeys.length; i++) {
await this.profileService.setCircle(pubKeys[i], 0);
}
}

countMembers(circle: Circle) {
return this.getFollowingInCircle(circle.id).length;
}

subscriptions: Subscription[] = [];

copy(text: string) {
copyToClipboard(text);

this.snackBar.open('Copied to clipboard', 'Hide', {
duration: 2500,
horizontalPosition: 'center',
verticalPosition: 'bottom',
});
}

getFollowingInCircle(id?: number) {
if (id == null) {
return this.profileService.following.filter(
(f) => f.circle == null || f.circle == 0
);
} else {
return this.profileService.following.filter((f) => f.circle == id);
}
}

copyPubKeys(circle: Circle) {
let pubkeys = this.getPublicKeys(circle);
pubkeys = pubkeys.map((k) => this.utilities.getNostrIdentifier(k));
this.copy(JSON.stringify(pubkeys));
}

copyPubKeysHex(circle: Circle) {
const pubkeys = this.getPublicKeys(circle);
this.copy(JSON.stringify(pubkeys));
}

private getPublicKeys(circle: Circle) {
const profiles = this.getFollowingInCircle(circle.id);
const pubkeys = profiles.map((p) => p.pubkey);
return pubkeys;
}

private getPublicPublicKeys() {
// console.log(this.items);
console.log(this.profileService.following);

const items: string[] = [];

for (let i = 0; i < this.circleService.circles.length; i++) {
const circle = this.circleService.circles[i];

if (circle.public) {
const profiles = this.getFollowingInCircle(circle.id);
const pubkeys = profiles.map((p) => p.pubkey);
items.push(...pubkeys);
}
}

return items;
}

getNpub(hex: string) {
return this.utilities.getNostrIdentifier(hex);
}

createCircle(): void {
const dialogRef = this.dialog.open(CircleDialog, {
data: { name: '', style: 1, public: true },
maxWidth: '100vw',
panelClass: 'full-width-dialog',
});

dialogRef.afterClosed().subscribe(async (result) => {
if (!result) {
return;
}

this.circleService.put(result);
});
}

project: any;

async ngOnInit() {
this.appState.updateTitle('Projects');
this.appState.showBackButton = true;
this.appState.actions = [];

this.subscriptions.push(
this.activatedRoute.paramMap.subscribe(async (params) => {
const id: any = params.get('id');
debugger;

if (!id) {
this.router.navigateByUrl('/projects');
return;
}

this.project = await this.apiService.project(id);
})
);

// this.subscriptions.push(this.profileService.items$.subscribe((profiles) => (this.following = profiles)) as Subscription);
}
}
14 changes: 7 additions & 7 deletions app/src/app/projects/projects.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@
<div class="feed-page">
<!-- <p>Circles is how you organize people you follow. Different circles can have different rules applied and circles is an important way to make the experience more enjoyable.</p> -->

<mat-card class="circle circle-container clickable" (click)="navigation.openFeed($event, circle)" *ngFor="let circle of projects">
<mat-card class="circle circle-container clickable" [routerLink]="['/projects', project._id]" *ngFor="let project of projects">
<div class="circle-item">
<!-- <mat-icon matListItemIcon [style.color]="circle.color">trip_origin</mat-icon> -->
<img [src]="circle.logo" class="project-logo">
<img [src]="project.logo" class="project-logo">
</div>
<div class="circle-item clickable">
{{ circle.name }}<br />
<span class="dimmed clickable"><span>{{ 'Circles.Count' | translate }}: {{ countMembers(circle) }}</span></span
{{ project.name }}<br />
<span class="dimmed clickable"><span>{{ 'Circles.Count' | translate }}: {{ countMembers(project) }}</span></span
><br />
<!-- <span class="dimmed clickable"><span *ngIf="circle.public">{{ 'Circles.Public' | translate }}</span> <span *ngIf="!circle.public">{{ 'Circles.Private' | translate }}</span> - {{ circle.style | circlestyle }} - {{ 'Circles.Created' | translate }}: {{ circle.created | ago }}</span> -->
</div>
Expand All @@ -24,18 +24,18 @@
<mat-icon>copy_all</mat-icon>
<span>{{ 'Circles.Copy' | translate }}</span>
</button>
<button *ngIf="circle.id" mat-menu-item (click)="deleteCircle(circle.id)">
<button *ngIf="project.id" mat-menu-item (click)="deleteCircle(project.id)">
<mat-icon>delete</mat-icon>
<span>{{ 'Circles.DeleteCircle' | translate }}</span>
</button>
</mat-menu>

<mat-menu #copyMenu="matMenu">
<button mat-menu-item (click)="copyPubKeys(circle)">
<button mat-menu-item (click)="copyPubKeys(project)">
<mat-icon>content_copy</mat-icon>
<span>{{ 'Circles.PublicKeysNpub' | translate }}</span>
</button>
<button mat-menu-item (click)="copyPubKeysHex(circle)">
<button mat-menu-item (click)="copyPubKeysHex(project)">
<mat-icon>content_copy</mat-icon>
<span>{{ 'Circles.PublicKeysHex' | translate }}</span>
</button>
Expand Down
Loading

0 comments on commit a5846f9

Please sign in to comment.