Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -22,16 +22,36 @@
</div>

<div class="flex flex-row justify-content-start gap-1">
<a class="social-link flex align-items-center justify-content-center" [href]="emailShareLink()">
<a
class="social-link flex align-items-center justify-content-center"
[href]="emailShareLink()"
target="_blank"
rel="noopener noreferrer"
>
<osf-icon [iconClass]="`fas fa-envelope fa-xl`" />
</a>
<a class="social-link flex align-items-center justify-content-center" [href]="twitterShareLink()">
<a
class="social-link flex align-items-center justify-content-center"
[href]="twitterShareLink()"
target="_blank"
rel="noopener noreferrer"
>
<osf-icon [iconClass]="`fab fa-x-twitter fa-xl`" />
</a>
<a class="social-link flex align-items-center justify-content-center" [href]="facebookShareLink()">
<a
class="social-link flex align-items-center justify-content-center"
[href]="facebookShareLink()"
target="_blank"
rel="noopener noreferrer"
>
<osf-icon [iconClass]="`fab fa-facebook-f fa-xl`" />
</a>
<a class="social-link flex align-items-center justify-content-center" [href]="linkedInShareLink()">
<a
class="social-link flex align-items-center justify-content-center"
[href]="linkedInShareLink()"
target="_blank"
rel="noopener noreferrer"
>
<osf-icon [iconClass]="`fab fa-linkedin-in fa-xl`" />
</a>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@ import { ButtonDirective } from 'primeng/button';
import { Card } from 'primeng/card';
import { Skeleton } from 'primeng/skeleton';

import { ChangeDetectionStrategy, Component, computed, input } from '@angular/core';
import { ChangeDetectionStrategy, Component, computed, inject, input } from '@angular/core';

import { PreprintProviderDetails } from '@osf/features/preprints/models';
import { PreprintSelectors } from '@osf/features/preprints/store/preprint';
import { IconComponent } from '@shared/components';

import { environment } from 'src/environments/environment';
import { ShareableContent } from '@shared/models';
import { SocialShareService } from '@shared/services';

@Component({
selector: 'osf-preprint-share-and-download',
Expand All @@ -24,6 +24,8 @@ import { environment } from 'src/environments/environment';
export class ShareAndDownloadComponent {
preprintProvider = input.required<PreprintProviderDetails | undefined>();

private readonly socialShareService = inject(SocialShareService);

preprint = select(PreprintSelectors.getPreprint);
isPreprintLoading = select(PreprintSelectors.isPreprintLoading);

Expand All @@ -40,65 +42,33 @@ export class ShareAndDownloadComponent {

if (!preprint) return '#';

return `${environment.webUrl}/download/${this.preprint()?.id}`;
return this.socialShareService.createDownloadUrl(preprint.id);
});

private preprintDetailsFullUrl = computed(() => {
private shareableContent = computed((): ShareableContent | null => {
const preprint = this.preprint();
const preprintProvider = this.preprintProvider();

if (!preprint || !preprintProvider) return '';
if (!preprint || !preprintProvider) return null;

return `${environment.webUrl}/preprints/${preprintProvider.id}/${preprint.id}`;
return {
id: preprint.id,
title: preprint.title,
description: preprint.description,
url: this.socialShareService.createPreprintUrl(preprint.id, preprintProvider.id),
};
});

emailShareLink = computed(() => {
const preprint = this.preprint();
const preprintProvider = this.preprintProvider();
shareLinks = computed(() => {
const content = this.shareableContent();

if (!preprint || !preprintProvider) return;
if (!content) return null;

const subject = encodeURIComponent(preprint.title);
const body = encodeURIComponent(this.preprintDetailsFullUrl());

return `mailto:?subject=${subject}&body=${body}`;
return this.socialShareService.generateAllSharingLinks(content);
});

twitterShareLink = computed(() => {
const preprint = this.preprint();
const preprintProvider = this.preprintProvider();

if (!preprint || !preprintProvider) return '';

const url = encodeURIComponent(this.preprintDetailsFullUrl());
const text = encodeURIComponent(preprint.title);

return `https://twitter.com/intent/tweet?url=${url}&text=${text}`;
});

facebookShareLink = computed(() => {
const preprint = this.preprint();
const preprintProvider = this.preprintProvider();

if (!preprint || !preprintProvider) return '';

const href = encodeURIComponent(this.preprintDetailsFullUrl());

const facebookAppId = preprintProvider.facebookAppId || environment.facebookAppId;
return `https://www.facebook.com/dialog/share?app_id=${facebookAppId}&display=popup&href=${href}`;
});

linkedInShareLink = computed(() => {
const preprint = this.preprint();
const preprintProvider = this.preprintProvider();

if (!preprint || !preprintProvider) return '';

const url = encodeURIComponent(this.preprintDetailsFullUrl());
const title = encodeURIComponent(preprint.title);
const summary = encodeURIComponent(preprint.description || preprint.title);
const source = encodeURIComponent('OSF');

return `https://www.linkedin.com/shareArticle?mini=true&url=${url}&title=${title}&summary=${summary}&source=${source}`;
});
emailShareLink = computed(() => this.shareLinks()?.email || '');
twitterShareLink = computed(() => this.shareLinks()?.twitter || '');
facebookShareLink = computed(() => this.shareLinks()?.facebook || '');
linkedInShareLink = computed(() => this.shareLinks()?.linkedIn || '');
}
Original file line number Diff line number Diff line change
Expand Up @@ -91,11 +91,11 @@
[pTooltip]="'project.overview.tooltips.share' | translate"
tooltipPosition="bottom"
>
<span class="font-bold">{{ socialsActionItems.length }}</span>
<span class="font-bold">{{ socialsActionItems().length }}</span>
<i class="fas fa-share-nodes text-2xl"></i>
<p-menu appendTo="body" #socialsActionMenu [model]="socialsActionItems" popup>
<p-menu appendTo="body" #socialsActionMenu [model]="socialsActionItems()" popup>
<ng-template #item let-item>
<a class="p-menu-item-link">
<a class="p-menu-item-link" [href]="item.url" target="_blank" rel="noopener noreferrer">
<div class="social-link flex align-items-center justify-content-center">
<osf-icon [iconClass]="`${item.icon} fa-sm`"></osf-icon>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,17 @@ import { Tooltip } from 'primeng/tooltip';
import { timer } from 'rxjs';

import { NgClass } from '@angular/common';
import { ChangeDetectionStrategy, Component, DestroyRef, effect, inject, input, signal } from '@angular/core';
import { ChangeDetectionStrategy, Component, computed, DestroyRef, effect, inject, input, signal } from '@angular/core';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { FormsModule } from '@angular/forms';
import { ActivatedRoute, Router, RouterLink } from '@angular/router';

import { DuplicateDialogComponent, TogglePublicityDialogComponent } from '@osf/features/project/overview/components';
import { SocialsShareActionItem } from '@osf/features/project/overview/models';
import { IconComponent } from '@osf/shared/components';
import { ToastService } from '@osf/shared/services';
import { SocialShareService, ToastService } from '@osf/shared/services';
import { ResourceType } from '@shared/enums';
import { ToolbarResource } from '@shared/models';
import { ShareableContent, ToolbarResource } from '@shared/models';
import { FileSizePipe } from '@shared/pipes';
import {
AddResourceToBookmarks,
Expand All @@ -30,7 +31,6 @@ import {
RemoveResourceFromBookmarks,
} from '@shared/stores';

import { SOCIAL_ACTION_ITEMS } from '../../constants';
import { ForkDialogComponent } from '../fork-dialog/fork-dialog.component';

@Component({
Expand All @@ -56,22 +56,28 @@ export class OverviewToolbarComponent {
private dialogService = inject(DialogService);
private translateService = inject(TranslateService);
private toastService = inject(ToastService);
private socialShareService = inject(SocialShareService);
protected destroyRef = inject(DestroyRef);
private readonly router = inject(Router);
private readonly route = inject(ActivatedRoute);
protected isPublic = signal(false);
protected isBookmarked = signal(false);

isCollectionsRoute = input<boolean>(false);
isAdmin = input.required<boolean>();
currentResource = input.required<ToolbarResource | null>();
projectTitle = input<string>('');
projectDescription = input<string>('');
showViewOnlyLinks = input<boolean>(true);

protected isBookmarksLoading = select(MyResourcesSelectors.getBookmarksLoading);
protected isBookmarksSubmitting = select(BookmarksSelectors.getBookmarksCollectionIdSubmitting);
protected bookmarksCollectionId = select(BookmarksSelectors.getBookmarksCollectionId);
protected bookmarkedProjects = select(MyResourcesSelectors.getBookmarks);
protected readonly socialsActionItems = SOCIAL_ACTION_ITEMS;
protected socialsActionItems = computed(() => {
const shareableContent = this.createShareableContent();
return shareableContent ? this.buildSocialActionItems(shareableContent) : [];
});

protected readonly forkActionItems = [
{
label: 'project.overview.actions.forkProject',
Expand Down Expand Up @@ -122,38 +128,6 @@ export class OverviewToolbarComponent {
});
}

private handleForkResource(): void {
const resource = this.currentResource();
const headerTranslation =
resource?.resourceType === ResourceType.Project
? 'project.overview.dialog.fork.headerProject'
: resource?.resourceType === ResourceType.Registration
? 'project.overview.dialog.fork.headerRegistry'
: '';
if (resource) {
this.dialogService.open(ForkDialogComponent, {
focusOnShow: false,
header: this.translateService.instant(headerTranslation),
closeOnEscape: true,
modal: true,
closable: true,
data: {
resource: resource,
},
});
}
}

private handleDuplicateProject(): void {
this.dialogService.open(DuplicateDialogComponent, {
focusOnShow: false,
header: this.translateService.instant('project.overview.dialog.duplicate.header'),
closeOnEscape: true,
modal: true,
closable: true,
});
}

protected handleToggleProjectPublicity(): void {
const resource = this.currentResource();
if (!resource) return;
Expand Down Expand Up @@ -212,4 +186,91 @@ export class OverviewToolbarComponent {
});
}
}

private handleForkResource(): void {
const resource = this.currentResource();
const headerTranslation =
resource?.resourceType === ResourceType.Project
? 'project.overview.dialog.fork.headerProject'
: resource?.resourceType === ResourceType.Registration
? 'project.overview.dialog.fork.headerRegistry'
: '';
if (resource) {
this.dialogService.open(ForkDialogComponent, {
focusOnShow: false,
header: this.translateService.instant(headerTranslation),
closeOnEscape: true,
modal: true,
closable: true,
data: {
resource: resource,
},
});
}
}

private handleDuplicateProject(): void {
this.dialogService.open(DuplicateDialogComponent, {
focusOnShow: false,
header: this.translateService.instant('project.overview.dialog.duplicate.header'),
closeOnEscape: true,
modal: true,
closable: true,
});
}

private createShareableContent(): ShareableContent | null {
const resource = this.currentResource();
const title = this.projectTitle();
const description = this.projectDescription();

if (!resource?.isPublic || !title) {
return null;
}

return {
id: resource.id,
title,
description,
url: this.buildResourceUrl(resource),
};
}

private buildResourceUrl(resource: ToolbarResource): string {
switch (resource.resourceType) {
case ResourceType.Project:
return this.socialShareService.createProjectUrl(resource.id);
case ResourceType.Registration:
return this.socialShareService.createRegistrationUrl(resource.id);
default:
return `${window.location.origin}/${resource.id}`;
}
}

private buildSocialActionItems(shareableContent: ShareableContent): SocialsShareActionItem[] {
const shareLinks = this.socialShareService.generateAllSharingLinks(shareableContent);

return [
{
label: 'project.overview.actions.socials.email',
icon: 'fas fa-envelope',
url: shareLinks.email,
},
{
label: 'project.overview.actions.socials.x',
icon: 'fab fa-x-twitter',
url: shareLinks.twitter,
},
{
label: 'project.overview.actions.socials.linkedIn',
icon: 'fab fa-linkedin',
url: shareLinks.linkedIn,
},
{
label: 'project.overview.actions.socials.facebook',
icon: 'fab fa-facebook-f',
url: shareLinks.facebook,
},
];
}
}
1 change: 0 additions & 1 deletion src/app/features/project/overview/constants/index.ts

This file was deleted.

This file was deleted.

1 change: 1 addition & 0 deletions src/app/features/project/overview/models/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export * from './project-overview.models';
export * from './socials-share-action-item.model';
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export interface SocialsShareActionItem {
label: string;
icon: string;
url: string;
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
<osf-overview-toolbar
[isCollectionsRoute]="isCollectionsRoute()"
[currentResource]="currentResource()"
[projectTitle]="project.title"
[projectDescription]="project.description"
[isAdmin]="isAdmin"
/>
</div>
Expand Down
Loading