Skip to content

Commit

Permalink
PER-9237 gift-storage-interface
Browse files Browse the repository at this point in the history
This pr's purpose is the implementation of the gift storage interface.

I have added a new tab to the dropdown for the gift component. I have created a new component which in which the new form lies where the user must input the email, amount and the message. Upon confirmation a new modal pops up for confirmation.
  • Loading branch information
crisnicandrei committed Jul 27, 2023
1 parent 2864e3b commit acee8a0
Show file tree
Hide file tree
Showing 14 changed files with 565 additions and 16 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<!-- @format -->
<div class="dialog-content">
<div class="header">
<span>Gift storage</span>
<button class="btn" (click)="onDoneClick()">
<i class="material-icons">close</i>
</button>
</div>
<div class="content">
<p class="popup-text">
<b
>Are you sure you would like to gift {{ amount }} GB of storage to
{{ email }}?</b
>
</p>
<p class="popup-text">
Once confirmed, the gift storage cannot be reclaimed.
<button class="btn btn-sm btn-primary" (click)="onConfirmClick()">
Confirm
</button>
<button class="btn btn-sm" (click)="onDoneClick()">Go back</button>
</p>
</div>
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
@import 'variables';

:host {
display: block;
width: 100%;
}

.header {
@include tabbedDialogHeader;
}

.content {
@include tabbedDialogContent;
flex-direction: column
}

.tabs {
@include tabbedDialogNav;
}

.panel {
@include tabbedDialogPanel;
}

.panel-title {
@include tabbedDialogPanelTitle;
}

form {
@include tabbedDialogPanelForm;
max-width: 600px;
padding-top: 0;
}

pr-archive-small {
margin-bottom: $grid-unit;

&.waiting {
opacity: 0.7;
}
}

.popup-text {
text-align: center;
padding: 20px;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
/* @format */
import {
ComponentFixture,
TestBed,
TestModuleMetadata,
} from '@angular/core/testing';
import { DialogRef, DIALOG_DATA } from '@root/app/dialog/dialog.module';
import { SharedModule } from '@shared/shared.module';
import * as Testing from '@root/test/testbedConfig';
import { cloneDeep } from 'lodash';
import { ConfirmGiftDialogComponent } from './confirm-gift-dialog.component';
import { Observable, Observer, Subject } from 'rxjs';

describe('ConfirmGiftDialogComponent', () => {
let component: ConfirmGiftDialogComponent;
let fixture: ComponentFixture<ConfirmGiftDialogComponent>;
let dialogRef: DialogRef;
let dialogData: {
email: string;
amount: string;
message: string;
giftResult: Observable<void>;
};

beforeEach(async () => {
const config: TestModuleMetadata = cloneDeep(Testing.BASE_TEST_CONFIG);

dialogData = {
email: '[email protected]',
amount: '10',
message: 'test message',
giftResult: new Observable(() => {}),
};

dialogRef = new DialogRef(1, null);

config.imports.push(SharedModule);
config.declarations.push(ConfirmGiftDialogComponent);
config.providers.push({
provide: DIALOG_DATA,
useValue: {
email: '[email protected]',
amount: 10,
message: 'test message',
giftResult: new Observable(() => {}),
},
});
config.providers.push({
provide: DialogRef,
useValue: dialogRef,
});
await TestBed.configureTestingModule(config).compileComponents();
});

beforeEach(() => {
fixture = TestBed.createComponent(ConfirmGiftDialogComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});

it('should create', () => {
expect(component).toBeTruthy();
});

it('should take the email from the dialog data', () => {
expect(component.email).toEqual('[email protected]');
});

it('should take the amount from the dialog data', () => {
expect(component.amount).toEqual(10);
});

it('should take the message from the dialog data', () => {
expect(component.message).toEqual('test message');
});

it('should close when close method is called', () => {
const dialogRefSpy = spyOn(dialogRef, 'close');

component.onDoneClick();

expect(dialogRefSpy).toHaveBeenCalled();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { BehaviorSubject } from 'rxjs';
/* @format */
import { Observable, Subscription } from 'rxjs';
import { Component, Inject, OnDestroy } from '@angular/core';
import { DialogRef, DIALOG_DATA } from '@root/app/dialog/dialog.service';
import { ApiService } from '@shared/services/api/api.service';
import { MessageService } from '@shared/services/message/message.service';

@Component({
selector: 'pr-confirm-gift-dialog',
templateUrl: './confirm-gift-dialog.component.html',
styleUrls: ['./confirm-gift-dialog.component.scss'],
})
export class ConfirmGiftDialogComponent {
email: string;
amount: number;
message: string;
giftResult: BehaviorSubject<boolean>;

constructor(
private dialogRef: DialogRef,
private api: ApiService,
@Inject(DIALOG_DATA) public data: any,
private msg: MessageService
) {
this.email = this.data.email;
this.amount = this.data.amount;
this.message = this.data.message;
this.giftResult = this.data.giftResult;
}

public onDoneClick(): void {
this.dialogRef.close();
}

public async onConfirmClick() {
try {
await this.api.billing.giftStorage(
this.email,
Number(this.amount)
);
this.giftResult.next(true)
} catch (e) {
this.msg.showError('Something went wrong! Please try again.');
this.giftResult.next(false)
}
this.dialogRef?.close();
}
}
102 changes: 102 additions & 0 deletions src/app/core/components/gift-storage/gift-storage.component.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
<!-- @format -->
<ng-container [ngSwitch]="isSuccessful">
<div *ngSwitchCase="false" class="gift-storage">
<p class="panel-title">Gift Storage</p>
<p>
Gift any amount of your unused storage to someone else. You can send
storage to both current Permanent users and those who do not yet have an
account; they must log in to/create an account in order to claim their
storage.
</p>
<form
[formGroup]="giftForm"
class="dialog-form"
(submit)="submitStorageGiftForm(giftForm.value)"
>
<div class="dialog-form-field">
<div class="text">
<label class="label" for="email">Recipient Email</label>
</div>
<input
type="text"
class="form-control"
id="email"
name="email"
formControlName="email"
placeholder="[email protected]"
/>
</div>
<div class="dialog-form-field dialog-form-field-amount">
<div class="text">
<label class="label" for="amount">Storage Gift Amount</label>
<span class="label-info">{{ this.availableSpace }} GB available</span>
</div>
<input
type="text"
class="form-control"
id="amount"
name="amount"
formControlName="amount"
placeholder="0"
/>
<span class="gigabytes">gigabytes</span>
</div>
<div class="dialog-form-field">
<div class="text">
<label class="label" for="amount">Note to recipient</label>
<span class="label-info">Optional</span>
</div>
<textarea
class="form-control"
id="message"
name="message"
formControlName="message"
placeholder="Write text here"
></textarea>
</div>
<div class="dialog-form-field">
<button
[disabled]="giftForm.invalid"
class="btn btn-primary"
[ngClass]="{ 'btn-disabled': giftForm.invalid }"
>
Send Gift Storage
</button>
</div>
</form>
</div>
<div class="gift-storage" *ngSwitchCase="true">
<svg
style="cursor: pointer"
(click)="closeSuccessMessage()"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<g clip-path="url(#clip0_30_1877)">
<path
d="M19 6.41L17.59 5L12 10.59L6.41 5L5 6.41L10.59 12L5 17.59L6.41 19L12 13.41L17.59 19L19 17.59L13.41 12L19 6.41Z"
fill="#646464"
/>
</g>
<defs>
<clipPath id="clip0_30_1877">
<rect width="24" height="24" fill="white" />
</clipPath>
</defs>
</svg>

<p class="panel-title">Storage successfully gifted</p>
<p>
Success! You sent {{ giftForm.value.amount }} GB of Permanent storage to
{{ giftForm.value.email }}.
</p>
<p>
You have
{{ (+(+availableSpace) - +(+giftForm.value.amount)).toFixed(2) }} GB of
storage available.
</p>
</div>
</ng-container>
87 changes: 87 additions & 0 deletions src/app/core/components/gift-storage/gift-storage.component.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
/* @format */
@import 'variables';

.gift-storage {
& > form {
margin: 0;
max-width: 800px;
}
}

.dialog-form-field {
display: flex;
margin-bottom: 23px;

@include beforeDesktop {
flex-direction: column;

& > div {
margin-bottom: 10px;
}
}

& .text {
width: 200px;
display: flex;
justify-content: center;
flex-direction: column;
}
& .label {
font-weight: 700;
font-family: 'Open-Sans', sans-serif;
margin: 0;
}

& .label-info {
font-family: 'Open Sans';
font-style: italic;
font-weight: 400;
font-size: 14px;
line-height: 17px;
}

& .gigabytes {
display: inline-flex;
align-items: center;

font-family: 'Open Sans';
font-style: normal;
font-weight: 400;
font-size: 16px;
line-height: 17px;
color: $gray-dark;
margin-left: 10px;

@include beforeDesktop {
margin-left: 0;
margin-top: 10px;
}
}

& > input,
textarea {
width: 400px;
border: 1px solid $gray-light;
border-radius: 6px;
height: 42px;
}

& > textarea {
height: 150px;
resize: none;
}

& .btn {
width: 200px;

&-disabled {
background-color: $gray-light;
color: $gray-dark;
border-color: $gray-light;
}
}
}

.panel-title {
@include tabbedDialogPanelTitle;
}
Loading

0 comments on commit acee8a0

Please sign in to comment.