Skip to content
Projects
Groups
Snippets
Help
Sign in / Register
Toggle navigation
Minds Frontend
Project overview
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Locked Files
Issues
344
Merge Requests
56
CI / CD
Security & Compliance
Packages
Wiki
Snippets
Members
Collapse sidebar
Close sidebar
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Minds
Minds Frontend
Compare Revisions
28f84e8445b9577650083e6e35af406da94f9940...f4b79682e7214da91469011a7022a1b04e293d26
Source
f4b79682e7214da91469011a7022a1b04e293d26
...
Target
28f84e8445b9577650083e6e35af406da94f9940
Compare
Commits (2)
Wallet token onboarding and settings
· 63afae3e
Olivia Madrid
authored
43 minutes ago
63afae3e
Merge branch 'token-onboarding-2331' into 'epic/wallet-80'
· f4b79682
Mark Harding
authored
43 minutes ago
Wallet token onboarding and settings See merge request
!698
f4b79682
Hide whitespace changes
Inline
Side-by-side
Showing
51 changed files
with
2259 additions
and
119 deletions
+2259
-119
package-lock.json
View file @
f4b79682
...
...
@@ -1980,11 +1980,6 @@
"integrity"
:
"sha512-K5K+yml8LTo9bWJI/rECfIPrGgxdpeNbj+d53lwN4QjW1MCwlkhUms+gtdzigTeUyBr09+u8BwOIY3MXvHdcsA=="
,
"dev"
:
true
},
"@types/video.js"
:
{
"version"
:
"7.3.3"
,
"resolved"
:
"https://registry.npmjs.org/@types/video.js/-/video.js-7.3.3.tgz"
,
"integrity"
:
"sha512-yAb46+4A0dKFxOQRVLoLyfC/S/BmHLE10MxPXt/t88+7R4GWLHosHelVtYpKBRykjptdkqfQXNRXoQzDeKm6MA=="
},
"@types/webpack-sources"
:
{
"version"
:
"0.1.5"
,
"resolved"
:
"https://registry.npmjs.org/@types/webpack-sources/-/webpack-sources-0.1.5.tgz"
,
...
...
This diff is collapsed.
src/app/app.component.html
View file @
f4b79682
...
...
@@ -33,6 +33,7 @@
[class.has-v2-navbar]=
"featuresService.has('top-feeds')"
[class.is-pro-domain]=
"isProDomain"
>
<m-emailConfirmation></m-emailConfirmation>
<m-announcement
[id]=
"'blockchain:sale'"
*ngIf=
"false"
>
<span
class=
"m-blockchain--wallet-address-notice--action"
...
...
This diff is collapsed.
src/app/common/common.module.ts
View file @
f4b79682
import
{
NgModule
}
from
'
@angular/core
'
;
import
{
CommonModule
as
NgCommonModule
}
from
'
@angular/common
'
;
import
{
RouterModule
,
Router
}
from
'
@angular/router
'
;
import
{
RouterModule
,
Router
,
Routes
}
from
'
@angular/router
'
;
import
{
FormsModule
,
ReactiveFormsModule
}
from
'
@angular/forms
'
;
import
{
MINDS_PIPES
}
from
'
./pipes/pipes
'
;
...
...
@@ -128,9 +128,17 @@ import { FormToastComponent } from './components/form-toast/form-toast.component
import
{
SsoService
}
from
'
./services/sso.service
'
;
import
{
ShadowboxHeaderTabsComponent
}
from
'
./components/shadowbox-header-tabs/shadowbox-header-tabs.component
'
;
import
{
TimespanFilterComponent
}
from
'
./components/timespan-filter/timespan-filter.component
'
;
import
{
EmailConfirmationComponent
}
from
'
./components/email-confirmation/email-confirmation.component
'
;
PlotlyModule
.
plotlyjs
=
PlotlyJS
;
const
routes
:
Routes
=
[
{
path
:
'
email-confirmation
'
,
redirectTo
:
'
/
'
,
},
];
@
NgModule
({
imports
:
[
NgCommonModule
,
...
...
@@ -139,6 +147,7 @@ PlotlyModule.plotlyjs = PlotlyJS;
FormsModule
,
ReactiveFormsModule
,
PlotlyModule
,
RouterModule
.
forChild
(
routes
),
],
declarations
:
[
MINDS_PIPES
,
...
...
@@ -245,6 +254,7 @@ PlotlyModule.plotlyjs = PlotlyJS;
ShadowboxSubmitButtonComponent
,
ShadowboxHeaderTabsComponent
,
TimespanFilterComponent
,
EmailConfirmationComponent
,
],
exports
:
[
MINDS_PIPES
,
...
...
@@ -346,6 +356,7 @@ PlotlyModule.plotlyjs = PlotlyJS;
ShadowboxSubmitButtonComponent
,
ShadowboxHeaderTabsComponent
,
TimespanFilterComponent
,
EmailConfirmationComponent
,
],
providers
:
[
SiteService
,
...
...
This diff is collapsed.
src/app/common/components/announcements/announcement.component.scss
View file @
f4b79682
...
...
@@ -67,4 +67,9 @@ m-announcement {
}
}
}
.m-announcement__clickable
{
cursor
:
pointer
;
font-weight
:
bold
;
}
}
This diff is collapsed.
src/app/common/components/announcements/announcement.component.ts
View file @
f4b79682
...
...
@@ -14,7 +14,7 @@ import { Client } from '../../../services/api';
<ng-content></ng-content>
</div>
<div class="m-announcement--close" (click)="close()">
<div class="m-announcement--close"
*ngIf="canClose"
(click)="close()">
<i class="material-icons">close</i>
</div>
</div>
...
...
@@ -24,6 +24,8 @@ export class AnnouncementComponent {
minds
:
Minds
=
window
.
Minds
;
hidden
:
boolean
=
false
;
@
Input
()
id
:
string
=
'
default
'
;
@
Input
()
canClose
:
boolean
=
true
;
@
Input
()
remember
:
boolean
=
true
;
constructor
(
private
storage
:
Storage
)
{}
...
...
@@ -32,7 +34,10 @@ export class AnnouncementComponent {
}
close
()
{
this
.
storage
.
set
(
'
hide-announcement:
'
+
this
.
id
,
true
);
if
(
this
.
remember
)
{
this
.
storage
.
set
(
'
hide-announcement:
'
+
this
.
id
,
true
);
}
this
.
hidden
=
true
;
}
}
This diff is collapsed.
src/app/common/components/email-confirmation/email-confirmation.component.html
0 → 100644
View file @
f4b79682
<ng-container
*ngIf=
"shouldShow"
>
<m-announcement
id=
"email-confirmation"
[canClose]=
"canClose"
[remember]=
"false"
>
Please confirm your email address.
<ng-container
*ngIf=
"!sent"
>
Didn't get it?
<span
class=
"m-announcement__clickable"
(click)=
"send()"
>
Click here to send again.
</span
></ng-container
>
</m-announcement>
</ng-container>
This diff is collapsed.
src/app/
modules/wallet/v2/action-button/action-button.component.html
→
src/app/
common/components/email-confirmation/email-confirmation.component.scss
View file @
f4b79682
File moved
This diff is collapsed.
src/app/common/components/email-confirmation/email-confirmation.component.ts
0 → 100644
View file @
f4b79682
import
{
ChangeDetectionStrategy
,
ChangeDetectorRef
,
Component
,
OnDestroy
,
OnInit
,
}
from
'
@angular/core
'
;
import
{
EmailConfirmationService
}
from
'
./email-confirmation.service
'
;
import
{
Session
}
from
'
../../../services/session
'
;
import
{
Subscription
}
from
'
rxjs
'
;
/**
* Component that displays an announcement-like banner
* asking the user to confirm their email address and a link
* to re-send the confirmation email.
* @see AnnouncementComponent
*/
@
Component
({
providers
:
[
EmailConfirmationService
],
selector
:
'
m-emailConfirmation
'
,
templateUrl
:
'
email-confirmation.component.html
'
,
changeDetection
:
ChangeDetectionStrategy
.
OnPush
,
})
export
class
EmailConfirmationComponent
implements
OnInit
,
OnDestroy
{
sent
:
boolean
=
false
;
shouldShow
:
boolean
=
false
;
canClose
:
boolean
=
false
;
protected
userEmitter$
:
Subscription
;
protected
canCloseTimer
:
number
;
protected
minds
=
window
.
Minds
;
constructor
(
protected
service
:
EmailConfirmationService
,
protected
session
:
Session
,
protected
cd
:
ChangeDetectorRef
)
{}
ngOnInit
():
void
{
this
.
setShouldShow
(
this
.
session
.
getLoggedInUser
());
this
.
userEmitter$
=
this
.
session
.
userEmitter
.
subscribe
(
user
=>
{
this
.
sent
=
false
;
this
.
setShouldShow
(
user
);
this
.
detectChanges
();
});
this
.
canCloseTimer
=
window
.
setTimeout
(()
=>
{
this
.
canClose
=
true
;
this
.
detectChanges
();
},
3000
);
}
ngOnDestroy
():
void
{
window
.
clearTimeout
(
this
.
canCloseTimer
);
if
(
this
.
userEmitter$
)
{
this
.
userEmitter$
.
unsubscribe
();
}
}
/**
* Re-calculates the visibility of the banner
* @param {Object} user
*/
setShouldShow
(
user
):
void
{
this
.
shouldShow
=
!
this
.
minds
.
from_email_confirmation
&&
user
&&
user
.
email_confirmed
===
false
;
}
/**
* Uses the service to re-send the confirmation email
*/
async
send
():
Promise
<
void
>
{
this
.
sent
=
true
;
this
.
detectChanges
();
try
{
const
sent
=
await
this
.
service
.
send
();
if
(
!
sent
)
{
this
.
sent
=
false
;
}
}
catch
(
e
)
{}
this
.
detectChanges
();
}
detectChanges
():
void
{
this
.
cd
.
markForCheck
();
this
.
cd
.
detectChanges
();
}
}
This diff is collapsed.
src/app/common/components/email-confirmation/email-confirmation.service.ts
0 → 100644
View file @
f4b79682
import
{
Injectable
}
from
'
@angular/core
'
;
import
{
Client
}
from
'
../../../services/api/client
'
;
/**
* API implementation service for Email Confirmation component
* @see EmailConfirmationComponent
*/
@
Injectable
()
export
class
EmailConfirmationService
{
constructor
(
protected
client
:
Client
)
{}
/**
* Attempts to re-send the confirmation email to the current logged in user
*/
async
send
():
Promise
<
boolean
>
{
const
response
=
(
await
this
.
client
.
post
(
'
api/v2/email/confirmation/resend
'
,
{}
))
as
any
;
return
Boolean
(
response
&&
response
.
sent
);
}
}
This diff is collapsed.
src/app/common/components/phone-input/phone-input.component.html
View file @
f4b79682
...
...
@@ -12,7 +12,9 @@
[(ngModel)]=
"phoneNumber"
(ngModelChange)=
"onPhoneNumberChange()"
[placeholder]=
"selectedCountry.placeHolder"
class=
"form-control m-phoneInput__input"
#input
required
autofocus
/>
</div>
This diff is collapsed.
src/app/common/components/phone-input/phone-input.component.scss
View file @
f4b79682
...
...
@@ -12,6 +12,10 @@ m-phone-input {
}
}
span
{
font-weight
:
300
;
}
.m-phone-input--wrapper
{
display
:
flex
;
@media
(
min-width
:
$max-mobile
)
{
...
...
@@ -70,6 +74,7 @@ m-phone-input {
cursor
:
pointer
;
border-top-left-radius
:
6px
;
border-bottom-left-radius
:
6px
;
outline
:
0
;
@include
m-theme
()
{
background-color
:
themed
(
$m-white
);
}
...
...
@@ -85,13 +90,13 @@ m-phone-input {
border-left
:
4px
solid
transparent
;
border-right
:
4px
solid
transparent
;
@include
m-theme
()
{
border-top
:
6px
solid
themed
(
$m-grey-
7
00
);
border-top
:
6px
solid
themed
(
$m-grey-
3
00
);
}
}
.m-phone-input--arrow.up
{
border-top
:
none
;
@include
m-theme
()
{
border-bottom
:
6px
solid
themed
(
$m-grey-
7
00
);
border-bottom
:
6px
solid
themed
(
$m-grey-
3
00
);
}
}
}
...
...
This diff is collapsed.
src/app/common/components/shadowbox-submit-button/shadowbox-submit-button.component.html
View file @
f4b79682
...
...
@@ -2,7 +2,14 @@
class=
"m-shadowboxSubmitButton"
type=
"submit"
[disabled]=
"disabled"
[ngClass]=
"{ saving: sav
eStatus === 'saving'
}"
[ngClass]=
"{ saving: sav
ing
}"
>
<ng-content></ng-content>
<div
*ngIf=
"!saving"
class=
"m-shadowboxSubmitButton__status--unsaved"
>
<ng-content></ng-content>
</div>
<div
*ngIf=
"saving"
class=
"m-shadowboxSubmitButton__status--saving"
>
<span></span>
<span></span>
<span></span>
</div>
</button>
This diff is collapsed.
src/app/common/components/shadowbox-submit-button/shadowbox-submit-button.component.ts
View file @
f4b79682
...
...
@@ -5,7 +5,7 @@ import { Component, Input } from '@angular/core';
templateUrl
:
'
./shadowbox-submit-button.component.html
'
,
})
export
class
ShadowboxSubmitButtonComponent
{
@
Input
()
sav
eStatus
:
string
=
'
unsaved
'
;
@
Input
()
sav
ing
:
boolean
=
false
;
@
Input
()
disabled
:
boolean
=
false
;
constructor
()
{}
...
...
This diff is collapsed.
src/app/modules/channels/explicit-overlay/overlay.component.html
View file @
f4b79682
<div
class=
"m-channel--explicit-overlay--container"
*ngIf=
"!hidden"
>
<div
class=
"m-channel--explicit-overlay--content"
>
<h3>
This channel contains
mature content
This channel contains
content that is NSFW
</h3>
<div
class=
"m-btn m-btn--slim m-btn--action m-channel--explicit-overlay--action"
...
...
This diff is collapsed.
src/app/modules/pro/channel/home/home.component.scss
View file @
f4b79682
...
...
@@ -51,6 +51,11 @@ m-proChannel__home {
@media
screen
and
(
max-width
:
$max-mobile
)
{
width
:
100%
;
}
>
*
{
min-width
:
0
;
min-height
:
0
;
}
}
.m-proChannelHome__featuredContent
{
...
...
This diff is collapsed.
src/app/modules/pro/channel/list/list.component.scss
View file @
f4b79682
...
...
@@ -88,6 +88,11 @@ m-pro--channel-list {
grid-template-columns
:
100%
;
}
>
*
{
min-width
:
0
;
min-height
:
0
;
}
&
.m-proChannelListContent__normalList
{
grid-template-columns
:
100%
;
...
...
This diff is collapsed.
src/app/modules/pro/settings/settings.component.html
View file @
f4b79682
...
...
@@ -899,27 +899,14 @@
[disabled]=
"
!form.valid || form.pristine || saveStatus === 'saving'
"
[sav
eStatus]=
"saveStatus
"
[sav
ing]=
"saveStatus === 'saving' ? true : false
"
>
<ng-container
[ngSwitch]=
"saveStatus"
>
<ng-template
ngSwitchCase=
"saving"
>
<div
class=
"m-shadowboxSubmitButton__status--saving"
>
<span></span>
<span></span>
<span></span>
</div>
</ng-template>
<ng-template
ngSwitchDefault
>
<div
class=
"m-shadowboxSubmitButton__status--unsaved"
>
Save
{{
activeTab === 'general'
? 'Personal Details'
: (activeTab | titlecase)
}}
</div>
</ng-template>
</ng-container>
Save
{{
activeTab === 'general'
? 'Personal Details'
: (activeTab | titlecase)
}}
</m-shadowboxSubmitButton>
</div>
</form>
...
...
This diff is collapsed.
src/app/modules/settings/emails/emails.component.html
View file @
f4b79682
...
...
@@ -37,9 +37,14 @@
id=
"email"
name=
"email"
[(ngModel)]=
"email"
(keyup)=
"change()"
(keyup)=
"change()
; changeEmail()
"
/>
</li>
<li
class=
"m-settings--emails-campaigns__note"
*ngIf=
"emailChanged"
i18n
>
Note: If you change your email address, it will need to be confirmed
again.
</li>
</ul>
</div>
...
...
This diff is collapsed.
src/app/modules/settings/emails/emails.component.scss
View file @
f4b79682
...
...
@@ -26,5 +26,15 @@ m-settings--emails {
margin-left
:
8px
;
}
}
.m-settings--emails-campaigns__note
{
font-size
:
0
.8em
;
line-height
:
1
;
padding
:
2px
8px
0
;
@include
m-theme
()
{
color
:
themed
(
$m-grey-300
);
}
}
}
}
This diff is collapsed.
src/app/modules/settings/emails/emails.component.ts
View file @
f4b79682
...
...
@@ -4,6 +4,7 @@ import { Subscription } from 'rxjs';
import
{
OverlayModalService
}
from
'
../../../services/ux/overlay-modal
'
;
import
{
ConfirmPasswordModalComponent
}
from
'
../../modals/confirm-password/modal.component
'
;
import
{
Session
}
from
'
../../../services/session
'
;
@
Component
({
selector
:
'
m-settings--emails
'
,
...
...
@@ -33,6 +34,7 @@ export class SettingsEmailsComponent implements OnInit {
error
:
string
=
''
;
changed
:
boolean
=
false
;
emailChanged
:
boolean
=
false
;
saved
:
boolean
=
false
;
inProgress
:
boolean
=
false
;
loading
:
boolean
=
false
;
...
...
@@ -41,7 +43,8 @@ export class SettingsEmailsComponent implements OnInit {
constructor
(
public
client
:
Client
,
public
overlayModal
:
OverlayModalService
public
overlayModal
:
OverlayModalService
,
protected
session
:
Session
)
{}
ngOnInit
()
{
...
...
@@ -77,6 +80,10 @@ export class SettingsEmailsComponent implements OnInit {
this
.
saved
=
false
;
}
changeEmail
()
{
this
.
emailChanged
=
true
;
}
canSubmit
()
{
return
this
.
changed
;
}
...
...
@@ -89,7 +96,13 @@ export class SettingsEmailsComponent implements OnInit {
notifications
:
this
.
notifications
,
})
.
then
((
response
:
any
)
=>
{
if
(
this
.
emailChanged
&&
window
.
Minds
.
user
)
{
window
.
Minds
.
user
.
email_confirmed
=
false
;
this
.
session
.
inject
(
window
.
Minds
.
user
);
}
this
.
changed
=
false
;
this
.
emailChanged
=
false
;
this
.
saved
=
true
;
this
.
error
=
''
;
...
...
This diff is collapsed.
src/app/modules/wallet/v2/action-button/action-button.component.scss
deleted
100644 → 0
View file @
28f84e84
This diff is collapsed.
src/app/modules/wallet/v2/action-button/action-button.component.ts
deleted
100644 → 0
View file @
28f84e84
import
{
Component
,
Input
}
from
'
@angular/core
'
;
@
Component
({
selector
:
'
m-walletActionButton
'
,
templateUrl
:
'
./action-button.component.html
'
,
})
export
class
WalletActionButtonComponent
{
@
Input
()
disabled
:
boolean
=
false
;
constructor
()
{}
}
This diff is collapsed.
src/app/modules/wallet/v2/balance-tokens/balance-tokens.component.html
View file @
f4b79682
...
...
@@ -14,7 +14,6 @@
>
</div>
</div>
<!-- <ng-container *ngTemplateOutlet="buyTokens"></ng-container> -->
<a
class=
"m-walletBalance--tokens__buyButtonWrapper"
routerLink=
"/tokens"
><m-shadowboxSubmitButton
[disabled]=
"!session.getLoggedInUser().rewards"
...
...
@@ -61,7 +60,9 @@
>
tokens
</div>
<a
*ngIf=
"session.getLoggedInUser().rewards"
>
Transfer to On-Chain
</a>
<a
*ngIf=
"session.getLoggedInUser().rewards"
(click)=
"showModal = true"
>
Transfer to On-Chain
</a
>
</div>
</div>
<div
class=
"m-walletBalance--tokens__learnMore"
>
...
...
@@ -75,16 +76,13 @@
tokens. Next payout in
<span>
{{ nextPayout | timediff }}
</span>
(Daily at 2:00am UTC)
</div>
<m-walletModal
[showModal]=
"showModal"
(closeModal)=
"showModal = false"
>
<m-walletOnchainTransfer
[offchainBalance]=
"offchainBalance.total"
[onchainAddress]=
"wallet.onchain.address"
></m-walletOnchainTransfer>
</m-walletModal>
</ng-container>
<!-- <ng-template #buyTokens>
<a class="m-walletBalance--tokens__buyButtonWrapper" routerLink="/tokens"
><m-shadowboxSubmitButton [disabled]="!session.getLoggedInUser().rewards"
>Buy tokens</m-shadowboxSubmitButton
></a
>
</ng-template> -->
<ng-template
#loading
>
<h2>
...
</h2>
</ng-template>
This diff is collapsed.
src/app/modules/wallet/v2/balance-tokens/balance-tokens.component.scss
View file @
f4b79682
m-walletBalance--tokens
{
display
:
block
;
max-width
:
700px
;
>
*
{
font-weight
:
300
;
font-size
:
15px
;
...
...
@@ -17,9 +18,11 @@ m-walletBalance--tokens {
flex-flow
:
row
wrap
;
}
.m-walletBalance--tokens__buyButtonWrapper
{
margin-left
:
36px
;
cursor
:
default
;
min-width
:
105px
;
m-shadowboxSubmitButton
{
margin-left
:
36px
;
}
}
.m-walletBalance--tokens__balanceTitle
{
position
:
relative
;
...
...
@@ -122,13 +125,28 @@ m-walletBalance--tokens {
}
}
m-shadowboxSubmitButton
{
min-width
:
105px
;
button
.m-shadowboxSubmitButton
{
height
:
35px
;
max-height
:
35px
;
min-width
:
0
;
min-height
:
0
;
}
.m-shadowboxSubmitButton__status--unsaved
{
line-height
:
15px
;
}
}
@media
screen
and
(
max-width
:
800px
)
{
.m-walletBalance--tokens__equationLeft
{
flex-direction
:
column
;
}
.m-walletBalance--tokens__buyButtonWrapper
{
margin-left
:
0
;
margin-top
:
22px
;
m-shadowboxSubmitButton
{
margin-left
:
0
;
margin-top
:
22px
;
}
}
}
@media
screen
and
(
max-width
:
$min-tablet
)
{
...
...
This diff is collapsed.
src/app/modules/wallet/v2/balance-tokens/balance-tokens.component.ts
View file @
f4b79682
...
...
@@ -29,6 +29,7 @@ export class WalletBalanceTokensV2Component implements OnInit, OnDestroy {
offchainBalance
;
onchainBalance
;
inProgress
=
true
;
showModal
=
false
;
protected
updateTimer$
;
nextPayout
;
...
...
@@ -43,7 +44,7 @@ export class WalletBalanceTokensV2Component implements OnInit, OnDestroy {
this
.
getPayout
();
this
.
inProgress
=
false
;
this
.
updateTimer$
=
setInterval
(
this
.
updateNextPayout
.
bind
(
this
),
60
000
);
this
.
updateTimer$
=
setInterval
(
this
.
updateNextPayout
.
bind
(
this
),
1
000
);
this
.
detectChanges
();
}
ngOnDestroy
()
{
...
...
This diff is collapsed.
src/app/modules/wallet/v2/chart/chart.component.ts
View file @
f4b79682
...
...
@@ -40,6 +40,7 @@ export class WalletChartComponent implements OnInit {
constructor
(
protected
walletService
:
WalletDashboardService
)
{}
// TODOOJM: use analytics dashboard response to control timespans and populate chart
ngOnInit
()
{
this
.
activeTimespan
=
this
.
timespans
[
0
];
this
.
data
[
'
visualisation
'
]
=
this
.
walletService
.
getTokenChart
(
...
...
This diff is collapsed.
src/app/modules/wallet/v2/dashboard.component.html
View file @
f4b79682
...
...
@@ -20,6 +20,12 @@
<div
class=
"m-shadowboxLayout__body"
>
<div
class=
"m-walletDashboardBalances__wrapper"
>
<!-- TODOOJM: make m-walletPhoneVerification have another output for success -- then trigger formToastService -->
<m-walletTokenOnboarding
*ngIf=
"activeCurrencyId === 'tokens' && !onboardingComplete"
(onboardingCompleted)=
"onboardingCompleted()"
(showTokenSettings)=
"updateView('settings')"
></m-walletTokenOnboarding>
<m-walletBalance--tokens
[wallet]=
"wallet"
class=
"m-shadowboxLayout__body"
...
...
@@ -27,7 +33,11 @@
></m-walletBalance--tokens>
</div>
<div
class=
"m-walletDashboardViews__wrapper"
>
<div
class=
"m-walletDashboardViews__tabsContainer"
>
<div
class=
"m-walletDashboardViews__tabsContainer"
*ngIf=
"views[activeCurrencyId].length > 1"
id=
"dashboardViewsTabs"
>
<div
class=
"m-walletDashboardViews__tab"
[ngClass]=
"{ active: view.id === activeViewId }"
...
...
@@ -38,9 +48,6 @@
</div>
</div>
<div
class=
"m-walletDashboardViews__viewsContainer"
>
<!-- <div class="m-walletDashboard__spinnerContainer" *ngIf="loading">
<div class="mdl-spinner mdl-js-spinner is-active" [mdl]></div>
</div> -->
<m-walletChart
class=
"m-walletDashboardViews__view"
*ngIf=
"
...
...
@@ -52,22 +59,26 @@
*ngIf=
"activeViewId === 'transactions'"
></m-walletTransactionsTable>
<ng-container
*ngIf=
"activeViewId === 'settings'"
>
<m-walletSettings--tokens
class=
"m-walletDashboardViews__view"
*ngIf=
"activeCurrencyId === 'tokens'"
></m-walletSettings--tokens>
<m-walletSettings--usd
class=
"m-walletDashboardViews__view"
*ngIf=
"activeCurrencyId === 'usd'"
></m-walletSettings--usd>
<m-walletSettings--eth
class=
"m-walletDashboardViews__view"
*ngIf=
"activeCurrencyId === 'eth'"
></m-walletSettings--eth>
<m-walletSettings--btc
class=
"m-walletDashboardViews__view"
*ngIf=
"activeCurrencyId === 'btc'"
></m-walletSettings--btc>
<div
class=
"m-walletDashboardSettings__wrapper"
>
<m-walletSettings--tokens
[wallet]=
"wallet"
class=
"m-walletDashboardViews__view"
*ngIf=
"activeCurrencyId === 'tokens'"
></m-walletSettings--tokens>
<m-walletSettings--usd
class=
"m-walletDashboardViews__view"
*ngIf=
"activeCurrencyId === 'usd'"
></m-walletSettings--usd>
<m-walletSettings--eth
class=
"m-walletDashboardViews__view"
*ngIf=
"activeCurrencyId === 'eth'"
(showTokenSettings)=
"updateView('settings')"
></m-walletSettings--eth>
<m-walletSettings--btc
class=
"m-walletDashboardViews__view"
*ngIf=
"activeCurrencyId === 'btc'"
></m-walletSettings--btc>
</div>
</ng-container>
</div>
</div>
...
...
This diff is collapsed.
src/app/modules/wallet/v2/dashboard.component.scss
View file @
f4b79682
...
...
@@ -32,6 +32,8 @@ m-walletDashboard {
font-size
:
15px
;
font-weight
:
300
;
line-height
:
20px
;
transition
:
all
0
.3s
cubic-bezier
(
0
.23
,
1
,
0
.32
,
1
);
@include
m-theme
()
{
color
:
themed
(
$m-grey-300
);
border-bottom
:
3px
solid
themed
(
$m-white
);
...
...
@@ -52,36 +54,417 @@ m-walletDashboard {
display
:
block
;
padding-bottom
:
50px
;
}
m-shadowboxSubmitButton
{
.m-shadowboxSubmitButton
{
max-height
:
35px
;
min-width
:
0
;
min-height
:
0
;
font-weight
:
300
;
padding
:
7px
15px
;
font-size
:
15px
;
line-height
:
20px
;
}
}
.m-walletDashboardBalances__wrapper
{
margin
:
50px
40px
34px
40
px
;
margin
:
50px
53px
34px
53
px
;
}
.m-walletDashboardViews__tabsContainer
{
margin
:
0
40px
;
}
.m-walletDashboardViews__view
{
margin
:
50px
57px
0
57px
;
transition
:
all
0
.3s
cubic-bezier
(
0
.23
,
1
,
0
.32
,
1
);
}
m-shadowboxSubmitButton
{
display
:
block
;
flex
:
0
1
auto
;
margin
:
0
0
0
21px
;
min-width
:
105px
;
box-sizing
:
border-box
;
.m-shadowboxSubmitButton
{
box-sizing
:
border-box
;
max-height
:
none
;
min-height
:
42px
;
height
:
42px
;
min-width
:
0
;
font-weight
:
300
;
padding
:
7px
15px
;
font-size
:
15px
;
line-height
:
20px
;
}
.m-shadowboxSubmitButton__status--unsaved
{
font-size
:
15px
;
line-height
:
20px
;
}
}
// *******************************************************
// ** DASHBOARD - MEDIA QUERIES **************************
// *******************************************************
@media
screen
and
(
max-width
:
$min-tablet
)
{
.m-walletDashboardBalances__wrapper
{
margin
:
50px
24px
34px
24px
;
}
.m-walletDashboardViews__tabsContainer
,
.m-walletDashboardViews__view
{
.m-walletDashboardViews__tabsContainer
{
margin-left
:
16px
;
margin-right
:
16px
;
}
.m-walletDashboardViews__view
{
margin
:
30px
24px
0
24px
;
}
}
@media
screen
and
(
max-width
:
$max-mobile
)
{
.m-walletDashboardViews__tab
{
padding
:
10px
9px
;
margin
:
0px
3px
;
}
}
// *******************************************************
// ** FORMS - COMMON STYLES ******************************
// *******************************************************
form
{
margin
:
0
;
padding
:
0
;
}
.m-walletForm__wrapper
{
display
:
flex
;
flex-flow
:
row
wrap
;
justify-content
:
flex-end
;
align-items
:
center
;
}
[
class
*=
'm-walletForm__field'
]
{
font-size
:
15px
;
line-height
:
20px
;
display
:
flex
;
flex-flow
:
column
nowrap
;
m-tooltip
{
margin-left
:
10px
;
.m-tooltip
{
margin
:
0
;
}
.m-tooltip--bubble
{
bottom
:
18px
;
margin-left
:
12px
;
font-weight
:
400
;
}
}
}
[
class
*=
'm-walletForm__row'
]
{
display
:
flex
;
flex-flow
:
row
wrap
;
box-sizing
:
border-box
;
&
[
class
*=
'--label'
]
{
font-size
:
15px
;
line-height
:
20px
;
margin
:
0
0
12px
0
;
align-items
:
center
;
flex-flow
:
row
nowrap
;
position
:
relative
;
@include
m-theme
()
{
color
:
themed
(
$m-grey-300
);
}
}
&
[
class
*=
'--validation'
]
{
margin-top
:
3px
;
min-height
:
22px
;
p
{
font-size
:
14px
;
line-height
:
19px
;
margin
:
0
;
font-weight
:
300
;
@include
m-theme
()
{
color
:
themed
(
$m-red-dark
);
}
}
}
}
.stretchedField
{
.m-walletForm__row--label
m-tooltip
{
margin-left
:
-12px
;
}
.m-walletForm__row--input
{
flex-flow
:
row
nowrap
;
&
.invalid
{
input
,
.m-phone-input--wrapper
{
@include
m-theme
()
{
border-color
:
themed
(
$m-red-dark
)
!
important
;
}
}
}
}
.m-walletForm__row--validation
{
align-self
:
flex-end
;
}
label
,
input
,
.m-walletForm__row--validation
{
flex
:
1
1
auto
;
max-width
:
auto
;
}
}
input
{
outline
:
0
;
font-size
:
15px
;
line-height
:
20px
;
font-weight
:
300
;
width
:
0
;
min-width
:
0
;
padding
:
10px
20px
;
border-radius
:
2px
;
cursor
:
text
;
@include
m-theme
()
{
color
:
themed
(
$m-grey-800
);
}
}
input
:not
(
.m-phoneInput__input
),
.m-phone-input--wrapper
{
border-radius
:
2px
;
@include
m-theme
()
{
box-shadow
:
0
1px
4px
0
rgba
(
themed
(
$m-black
)
,
0
.1
);
border
:
1px
solid
themed
(
$m-grey-50
);
}
&
:focus
{
&
:not
(
:read-only
)
{
@include
m-theme
()
{
border-color
:
themed
(
$m-blue
);
}
}
}
}
.m-walletForm__fieldsContainer
{
flex
:
1
1
auto
;
}
m-phone-input
{
margin-bottom
:
0
;
.m-phone-input--wrapper
{
width
:
100%
;
min-width
:
240px
;
justify-content
:
flex-start
;
align-items
:
center
;
}
m-phone-input--country
{
flex
:
0
1
auto
;
}
input
{
flex
:
1
1
auto
;
padding
:
10px
;
border-bottom-left-radius
:
0
;
border-top-left-radius
:
0
;
@include
m-theme
()
{
border-left
:
1px
solid
themed
(
$m-grey-50
);
}
}
}
@media
screen
and
(
max-width
:
500px
)
{
m-shadowboxSubmitButton
{
margin
:
21px
0
0
0
;
}
.stretchedField
{
.m-walletForm__row--label
m-tooltip
{
.m-tooltip--bubble
{
right
:
12px
;
}
}
[
class
*=
'm-walletForm__row'
]
{
flex-flow
:
row
wrap
;
label
,
input
{
flex
:
1
1
100%
;
min-width
:
100%
;
max-width
:
100%
;
}
m-phone-input
input
{
min-width
:
none
;
}
}
}
}
}
// *******************************************************
// ** SETTINGS - COMMON STYLES ***************************
// *******************************************************
.m-walletSettings
{
// font-weight: 300;
@include
m-theme
()
{
color
:
themed
(
$m-grey-800
);
}
m-shadowboxSubmitButton
{
margin
:
27px
0
0
0
;
}
h2
{
margin
:
0
;
font-size
:
26px
;
line-height
:
34px
;
}
h4
{
margin
:
0
;
font-size
:
21px
;
line-height
:
28px
;
}
ul
{
list-style
:
none
;
margin
:
0
;
padding
:
0
;
// font-weight: 300;
}
a
{
// font-weight: 300;
text-decoration
:
underline
;
cursor
:
pointer
;
font-size
:
14px
;
line-height
:
19px
;
}
p
{
font-size
:
14px
;
line-height
:
19px
;
margin
:
23px
0
0
0
;
// font-weight: 300;
@include
m-theme
()
{
color
:
themed
(
$m-grey-300
);
}
}
input
{
outline
:
0
;
font-size
:
15px
;
line-height
:
20px
;
font-weight
:
300
;
width
:
0
;
min-width
:
0
;
padding
:
10px
20px
;
border-radius
:
2px
;
cursor
:
text
;
@include
m-theme
()
{
color
:
themed
(
$m-grey-800
);
box-shadow
:
0
1px
4px
0
rgba
(
themed
(
$m-black
)
,
0
.1
);
border
:
1px
solid
themed
(
$m-grey-50
);
}
&
:focus
{
&
:not
(
:read-only
)
{
@include
m-theme
()
{
border-color
:
themed
(
$m-blue
);
}
}
}
}
.m-walletSettingsView--addressCurrent
{
h2
{
margin-bottom
:
23px
;
}
}
.m-walletSettings__setupOptions__recommendation
{
display
:
flex
;
flex-flow
:
row
nowrap
;
align-items
:
flex-end
;
font-size
:
12px
;
line-height
:
16px
;
margin
:
31px
0
0
0
;
@include
m-theme
()
{
color
:
themed
(
$m-grey-300
);
}
i
{
font-size
:
18px
;
margin-right
:
8px
;
}
}
.m-walletSettingsView__setupOptions__container
{
display
:
flex
;
flex-flow
:
row
wrap
;
li
{
box-sizing
:
border-box
;
flex
:
1
1
50%
;
padding
:
16px
0
16px
54px
;
}
p
{
@include
m-theme
()
{
color
:
themed
(
$m-grey-800
);
}
}
.m-walletSettingsView__setupOption--custom
{
div
{
margin-top
:
16px
;
display
:
inline-block
;
a
,
span
{
display
:
inline-block
;
margin-right
:
5px
;
}
span
{
@include
m-theme
()
{
color
:
themed
(
$m-grey-300
);
}
}
}
}
.m-walletSettingsView__setupOption--metamask
{
padding-right
:
32px
;
padding-left
:
0
;
border-width
:
0
;
border-right-width
:
1px
;
border-style
:
solid
;
@include
m-theme
()
{
border-image
:
linear-gradient
(
transparent
,
rgba
(
themed
(
$m-grey-200
)
,
0
.6
)
,
transparent
)
10
100%
;
}
}
div
{
display
:
flex
;
flex-flow
:
row
nowrap
;
align-items
:
center
;
img
{
height
:
34px
;
margin-right
:
12px
;
}
}
}
span
.m-walletSettings__address--emphasis
{
@include
m-theme
()
{
color
:
themed
(
$m-grey-800
);
}
}
a
.m-walletSettings__backButton
{
margin-top
:
33px
;
display
:
flex
;
flex-flow
:
row
nowrap
;
align-items
:
flex-end
;
text-decoration
:
none
;
i
{
font-size
:
18px
;
margin-right
:
5px
;
}
&
:hover
{
span
{
text-decoration
:
underline
;
}
}
}
@media
screen
and
(
max-width
:
$min-tablet
)
{
.m-walletSettingsView__setupOptions__container
{
li
.m-walletSettingsView__setupOption--custom
{
padding-left
:
32px
;
}
}
}
@media
screen
and
(
max-width
:
520px
)
{
.m-walletSettingsView__setupOptions__container
{
li
{
flex-basis
:
100%
;
&
.m-walletSettingsView__setupOption--metamask
{
padding
:
16px
0
32px
0
;
border-right-width
:
0
;
}
&
.m-walletSettingsView__setupOption--custom
{
padding
:
32px
0
0
0
;
}
}
}
}
}
This diff is collapsed.
src/app/modules/wallet/v2/dashboard.component.ts
View file @
f4b79682
...
...
@@ -4,8 +4,9 @@ import {
OnDestroy
,
ChangeDetectionStrategy
,
ChangeDetectorRef
,
ComponentFactoryResolver
,
}
from
'
@angular/core
'
;
import
{
Sub
ject
,
Sub
scription
}
from
'
rxjs
'
;
import
{
Subscription
}
from
'
rxjs
'
;
import
{
WalletDashboardService
}
from
'
./dashboard.service
'
;
import
{
Session
}
from
'
../../../services/session
'
;
import
{
ActivatedRoute
,
Router
,
ParamMap
}
from
'
@angular/router
'
;
...
...
@@ -13,6 +14,7 @@ import { MindsTitle } from '../../../services/ux/title';
import
sidebarMenu
from
'
./sidebar-menu.default
'
;
import
{
Menu
}
from
'
../../../common/components/sidebar-menu/sidebar-menu.component
'
;
import
{
ShadowboxHeaderTab
}
from
'
../../../interfaces/dashboard
'
;
import
{
Storage
}
from
'
../../../services/storage
'
;
@
Component
({
selector
:
'
m-walletDashboard
'
,
...
...
@@ -22,10 +24,11 @@ import { ShadowboxHeaderTab } from '../../../interfaces/dashboard';
export
class
WalletDashboardComponent
implements
OnInit
,
OnDestroy
{
menu
:
Menu
=
sidebarMenu
;
paramsSubscription
:
Subscription
;
wallet
;
wallet
=
{}
;
activeCurrencyId
:
string
;
activeViewId
:
string
;
onboardingComplete
=
false
;
views
:
any
=
{
tokens
:
[
...
...
@@ -49,7 +52,8 @@ export class WalletDashboardComponent implements OnInit, OnDestroy {
protected
router
:
Router
,
protected
route
:
ActivatedRoute
,
protected
cd
:
ChangeDetectorRef
,
protected
title
:
MindsTitle
protected
title
:
MindsTitle
,
protected
storage
:
Storage
)
{}
ngOnInit
()
{
...
...
@@ -58,6 +62,14 @@ export class WalletDashboardComponent implements OnInit, OnDestroy {
return
;
}
if
(
this
.
storage
.
get
(
'
walletOnboardingComplete
'
)
||
(
this
.
session
.
getLoggedInUser
().
rewards
&&
this
.
session
.
getLoggedInUser
().
eth_wallet
)
)
{
this
.
onboardingComplete
=
true
;
}
this
.
title
.
setTitle
(
'
Wallet
'
);
this
.
wallet
=
this
.
walletService
.
getWallet
();
...
...
@@ -121,6 +133,12 @@ export class WalletDashboardComponent implements OnInit, OnDestroy {
this
.
detectChanges
();
}
onboardingCompleted
()
{
this
.
storage
.
set
(
'
walletOnboardingComplete
'
,
true
);
this
.
onboardingComplete
=
true
;
this
.
detectChanges
();
}
detectChanges
()
{
this
.
cd
.
markForCheck
();
this
.
cd
.
detectChanges
();
...
...
This diff is collapsed.
src/app/modules/wallet/v2/dashboard.service.ts
View file @
f4b79682
...
...
@@ -65,6 +65,8 @@ export class WalletDashboardService {
protected
session
:
Session
)
{}
// TODOOJM: make wallet an observable and have the dashboard component subscribe to it
// TODOOJM: make functions to
getWallet
()
{
this
.
getTokenAccounts
();
this
.
getEthAccount
();
...
...
@@ -80,6 +82,8 @@ export class WalletDashboardService {
async
getTokenAccounts
()
{
await
this
.
loadOffchainAndReceiver
();
await
this
.
loadOnchain
();
const
tokenTypes
=
[
'
tokens
'
,
'
onchain
'
,
'
offchain
'
];
// receiver?
// TODOOJM iterate through this.wallet and return walletObj where key matches one of the tokenTypes
}
async
loadOffchainAndReceiver
()
{
...
...
@@ -137,6 +141,7 @@ export class WalletDashboardService {
if
(
ethBalance
)
{
this
.
wallet
.
eth
.
balance
=
ethBalance
;
}
return
this
.
wallet
.
eth
;
}
async
getStripeAccount
()
{
...
...
@@ -181,8 +186,8 @@ export class WalletDashboardService {
return
fakeData
.
visualisation
;
}
// TODOOJM tx/contribution endpoint needed
getTokenTransactionTable
()
{
// TODOOJM get this from contributions component
return
fakeData
.
token_transactions
;
}
}
This diff is collapsed.
src/app/modules/wallet/v2/modal/modal.component.html
0 → 100644
View file @
f4b79682
<div
*ngIf=
"_showModal"
class=
"m-walletModal__container"
>
<div
class=
"m-walletModal__backdrop"
></div>
<div
class=
"m-walletModal__close"
(click)=
"close()"
>
<i
class=
"material-icons"
>
close
</i>
</div>
<div
class=
"m-walletModal"
(click)=
"clickedModal($event)"
>
<div
class=
"m-walletModal__content"
>
<ng-content></ng-content>
</div>
</div>
</div>
This diff is collapsed.
src/app/modules/wallet/v2/modal/modal.component.scss
0 → 100644
View file @
f4b79682
m-walletModal
{
.m-walletModal__container
{
display
:
block
;
position
:
fixed
;
top
:
0
;
bottom
:
0
;
left
:
0
;
right
:
0
;
height
:
100%
;
width
:
100%
;
overflow
:
scroll
;
z-index
:
9999999
;
}
.m-walletModal__backdrop
{
position
:
fixed
;
top
:
0
;
left
:
0
;
width
:
100%
;
height
:
100%
;
z-index
:
9999995
;
@include
m-theme
()
{
background-color
:
rgba
(
themed
(
$m-white
)
,
0
.6
);
}
}
.m-walletModal
{
padding
:
56px
65px
;
z-index
:
9999996
;
position
:
fixed
;
transform
:
translateY
(
-50%
);
width
:
70vw
;
max-width
:
700px
;
max-height
:
90vh
;
right
:
2vw
;
left
:
2vw
;
margin
:
auto
;
box-sizing
:
border-box
;
top
:
50%
;
overflow-y
:
auto
;
transition
:
all
0
.3s
cubic-bezier
(
0
.23
,
1
,
0
.32
,
1
);
@include
m-theme
()
{
box-shadow
:
0
12px
24px
rgba
(
themed
(
$m-black
)
,
0
.3
);
background-color
:
themed
(
$m-white
);
color
:
themed
(
$m-grey-300
);
}
a
{
text-decoration
:
underline
;
cursor
:
pointer
;
display
:
inline-block
;
font-weight
:
300
;
}
}
.m-walletModal__title
{
font-weight
:
500
;
font-size
:
24px
;
line-height
:
32px
;
margin-bottom
:
18px
;
@include
m-theme
()
{
color
:
themed
(
$m-grey-800
);
}
}
.m-walletModal__desc
{
margin-bottom
:
30px
;
p
{
font-size
:
16px
;
line-height
:
21px
;
}
}
[
class
*=
'm-walletModal__footnote--'
]
{
margin
:
10px
0
11px
0
;
font-size
:
15px
;
line-height
:
20px
;
}
.m-walletModal__close
{
z-index
:
9999998
;
line-height
:
normal
;
cursor
:
pointer
;
box-sizing
:
border-box
;
position
:
fixed
;
height
:
53px
;
width
:
53px
;
right
:
25px
;
top
:
25px
;
padding
:
4px
;
display
:
inline-block
;
border-radius
:
50%
;
cursor
:
pointer
;
transition
:
all
0
.5s
cubic-bezier
(
0
.23
,
1
,
0
.32
,
1
);
@include
m-theme
()
{
background-color
:
themed
(
$m-white
);
box-shadow
:
0
0
15px
0
rgba
(
themed
(
$m-black
)
,
0
.25
);
}
i
{
position
:
absolute
;
top
:
50%
;
left
:
50%
;
margin-top
:
-25%
;
transform
:
translate
(
-50%
);
font-size
:
28px
;
opacity
:
0
.3
;
transition
:
opacity
0
.5s
cubic-bezier
(
0
.23
,
1
,
0
.32
,
1
);
}
&
:hover
{
transform
:
scale
(
1
.05
);
@include
m-theme
()
{
box-shadow
:
0
0
8px
0
rgba
(
themed
(
$m-black
)
,
0
.22
);
}
i
{
opacity
:
0
.6
;
}
}
}
@media
screen
and
(
max-width
:
$min-tablet
)
{
.m-walletModal
{
padding
:
46px
50px
;
max-width
:
80vw
;
max-height
:
90vh
;
}
}
@media
screen
and
(
max-width
:
$max-mobile
)
{
.m-walletModal
{
padding
:
26px
35px
;
max-width
:
90vw
;
max-height
:
95vh
;
}
}
}
This diff is collapsed.
src/app/modules/wallet/v2/modal/modal.component.ts
0 → 100644
View file @
f4b79682
import
{
Component
,
Output
,
Input
,
EventEmitter
,
OnDestroy
,
HostListener
,
}
from
'
@angular/core
'
;
@
Component
({
selector
:
'
m-walletModal
'
,
templateUrl
:
'
./modal.component.html
'
,
})
export
class
WalletModalComponent
implements
OnDestroy
{
showModalTimeout
:
any
=
null
;
justOpened
=
true
;
public
_showModal
=
false
;
@
Input
()
public
set
showModal
(
val
:
boolean
)
{
this
.
_showModal
=
val
;
val
?
this
.
show
()
:
this
.
close
();
}
@
Output
()
closeModal
:
EventEmitter
<
any
>
=
new
EventEmitter
();
constructor
()
{}
show
()
{
if
(
document
&&
document
.
body
)
{
this
.
justOpened
=
true
;
document
.
body
.
classList
.
add
(
'
m-overlay-modal--shown--no-scroll
'
);
// Prevent dismissal of modal when it's just been opened
this
.
showModalTimeout
=
setTimeout
(()
=>
{
this
.
justOpened
=
false
;
},
20
);
}
}
// * MODAL DISMISSAL * --------------------------------------------------------------------------
// Dismiss modal when backdrop is clicked and modal is open
@
HostListener
(
'
document:click
'
,
[
'
$event
'
])
clickedBackdrop
(
$event
)
{
if
(
this
.
_showModal
&&
!
this
.
justOpened
)
{
$event
.
preventDefault
();
$event
.
stopPropagation
();
this
.
close
();
}
}
// Don't dismiss modal if click somewhere other than backdrop
clickedModal
(
$event
)
{
$event
.
stopPropagation
();
}
close
()
{
document
.
body
.
classList
.
remove
(
'
m-overlay-modal--shown--no-scroll
'
);
this
.
closeModal
.
emit
();
}
ngOnDestroy
()
{
if
(
this
.
showModalTimeout
)
{
clearTimeout
(
this
.
showModalTimeout
);
}
this
.
close
();
}
}
This diff is collapsed.
src/app/modules/wallet/v2/onchain-transfer/onchain-transfer.component.html
0 → 100644
View file @
f4b79682
<div
class=
"m-walletModal__title"
>
On-Chain Transfer
</div>
<div
class=
"m-walletModal__desc"
>
<!-- TODOOJM convert balance into number in .ts and use template format like this: {available, plural, =1
{{{available | number}} token} other {{{available | number}} tokens}}' (full example commented below)-->
<p>
You can request to withdraw up to
<span
class=
"m-walletOnchainTransfer__offchainBalance"
>
{{ offchainBalance | token: 18 | number: '1.0-3' }} tokens
</span
>
from your rewards to your on-chain wallet below.
</p>
<p
class=
"m-walletOnchainTransfer__gasNotice"
>
Note: a small amount of ETH will be charged to cover the transaction fee.
Withdrawals go through an approval process and may take up to 72 hours to
complete.
</p>
</div>
<!-- TODOOJM does keyup duplicate the transfer() function trigger?-->
<!-- <form [formGroup]="form" (ngSubmit)="transfer()" (keyup.enter)="transfer()"> -->
<form
[formGroup]=
"form"
(keyup.enter)=
"transfer()"
>
<div
class=
"m-walletForm__wrapper"
>
<div
class=
"m-walletForm__fieldsContainer"
>
<div
class=
"m-walletForm__field--text stretchedField"
>
<div
class=
"m-walletForm__row--label"
>
<label
for=
"amount"
i18n
>
Amount
</label>
<m-tooltip
icon=
"help"
>
<ng-container
i18n
>
Placeholder
</ng-container>
</m-tooltip>
</div>
<div
class=
"m-walletForm__row--input"
[ngClass]=
"{ invalid: invalid }"
>
<input
type=
"number"
id=
"amount"
name=
"amount"
formControlName=
"amount"
class=
"form-control"
autofocus
/>
</div>
<div
class=
"m-walletForm__row--validation"
>
<p
*ngIf=
"invalid"
>
🚧 This doesn't do anything yet 🚧
</p>
</div>
</div>
</div>
<m-shadowboxSubmitButton
[disabled]=
"inProgress || invalid"
[saving]=
"inProgress"
(click)=
"transfer()"
>
Transfer
</m-shadowboxSubmitButton>
</div>
</form>
<!-- TODOOJM -->
<!-- <div
class="m-border mdl-color--white m-token-withdraw"
*ngIf="session.getLoggedInUser().rewards"
>
<p i18n>
You can request to withdraw up to {available, plural, =1
{{{available | number}} token} other {{{available | number}} tokens}} from
your rewards to your <b>OnChain</b> wallet below.
</p>
<p *ngIf="withholding" i18n>
{withholding, plural, =1
{{{withholding | number}} token} other {{{withholding | number}} tokens}}
are unavailable due to credit card payment. They will be released after 30
days the payment occurred.
</p>
<p class="m-token-withdraw__note" i18n>
Note: a small amount of ETH will be charged to cover the transaction fee.
Withdrawals <b>go through an approval process</b>
and may take up to 72 hours to complete.
</p>
<div class="m-token-withdraw--form">
<input
type="text"
class="m-token-withdraw--input"
[disabled]="inProgress"
[ngModel]="amount | number"
(ngModelChange)="setAmount($event)"
/>
<button
class="m-token-withdraw--submit-button"
[disabled]="!canWithdraw()"
(click)="withdraw()"
i18n="@@WALLET__TOKENS__WITHDRAW__WITHDRAW_ACTION"
>
Withdraw
</button>
<div
*ngIf="inProgress"
class="mdl-spinner mdl-js-spinner is-active"
[mdl]
></div>
</div>
<p class="m-token-withdraw--error" *ngIf="!!error">
{{ error }}
</p>
</div>
<m-wallet-token--withdraw-ledger
[preview]="true"
></m-wallet-token--withdraw-ledger> -->
This diff is collapsed.
src/app/modules/wallet/v2/onchain-transfer/onchain-transfer.component.scss
0 → 100644
View file @
f4b79682
m-walletOnchainTransfer
{
.m-walletOnchainTransfer__offchainBalance
{
@include
m-theme
()
{
color
:
themed
(
$m-grey-800
);
}
}
p
.m-walletOnchainTransfer__gasNotice
{
font-size
:
15px
;
line-height
:
20px
;
}
}
This diff is collapsed.
src/app/modules/wallet/v2/onchain-transfer/onchain-transfer.component.ts
0 → 100644
View file @
f4b79682
import
{
Component
,
OnInit
,
Input
}
from
'
@angular/core
'
;
import
{
FormBuilder
}
from
'
@angular/forms
'
;
import
{
Client
}
from
'
../../../../services/api
'
;
import
{
Session
}
from
'
../../../../services/session
'
;
import
{
FormToastService
}
from
'
../../../../common/services/form-toast.service
'
;
@
Component
({
selector
:
'
m-walletOnchainTransfer
'
,
templateUrl
:
'
./onchain-transfer.component.html
'
,
})
export
class
WalletOnchainTransferComponent
implements
OnInit
{
@
Input
()
offchainBalance
;
@
Input
()
onchainAddress
;
inProgress
;
invalid
;
transferComplete
=
false
;
form
=
this
.
fb
.
group
({
amount
:
[
this
.
offchainBalance
],
address
:
[
this
.
onchainAddress
],
});
constructor
(
protected
session
:
Session
,
private
formToastService
:
FormToastService
,
private
fb
:
FormBuilder
,
protected
client
:
Client
)
{}
ngOnInit
()
{}
transfer
()
{
// TODOOJM
this
.
invalid
=
true
;
}
}
// TODOOJM move this over
// import {
// ChangeDetectionStrategy,
// ChangeDetectorRef,
// Component,
// ViewChild,
// } from '@angular/core';
// import { Client } from '../../../../services/api/client';
// import { WithdrawContractService } from '../../../blockchain/contracts/withdraw-contract.service';
// import { Session } from '../../../../services/session';
// import { WalletTokenWithdrawLedgerComponent } from './ledger/ledger.component';
// import { Web3WalletService } from '../../../blockchain/web3-wallet.service';
// @Component({
// moduleId: module.id,
// selector: 'm-wallet-token--withdraw',
// templateUrl: 'withdraw.component.html',
// changeDetection: ChangeDetectionStrategy.OnPush,
// })
// export class WalletTokenWithdrawComponent {
// inProgress: boolean = false;
// balance: number = 0;
// available: number = 0;
// amount: number = 0;
// error: string = '';
// hasWithdrawnToday: boolean = false;
// withholding: number = 0;
// @ViewChild(WalletTokenWithdrawLedgerComponent, { static: true })
// protected ledgerComponent: WalletTokenWithdrawLedgerComponent;
// constructor(
// protected client: Client,
// protected cd: ChangeDetectorRef,
// public session: Session,
// protected contract: WithdrawContractService,
// protected web3Wallet: Web3WalletService
// ) {}
// async ngOnInit() {
// this.load();
// try {
// await this.checkPreviousWithdrawals();
// } catch (e) {
// this.error = 'You can only withdraw once a day';
// }
// }
// async load() {
// this.inProgress = true;
// this.error = '';
// this.detectChanges();
// try {
// let response: any = await this.client.get(
// `api/v2/blockchain/wallet/balance`
// );
// if (response && typeof response.addresses !== 'undefined') {
// this.balance = response.addresses[1].balance / Math.pow(10, 18);
// this.available = response.addresses[1].available / Math.pow(10, 18);
// if (this.balance > this.available) {
// this.withholding = this.balance - this.available;
// }
// this.setAmount(this.available);
// } else {
// this.error = 'Server error';
// }
// } catch (e) {
// console.error(e);
// this.error = (e && e.message) || 'Server error';
// } finally {
// this.inProgress = false;
// this.detectChanges();
// }
// }
// async checkPreviousWithdrawals() {
// let response: any = await this.client.post(
// 'api/v2/blockchain/transactions/can-withdraw'
// );
// if (!response.canWithdraw) {
// this.hasWithdrawnToday = true;
// throw new Error('You can only withdraw once a day');
// }
// }
// setAmount(amount: number | string) {
// if (!amount) {
// this.amount = 0;
// return;
// }
// if (typeof amount === 'number') {
// this.amount = amount;
// this.detectChanges();
// return;
// }
// amount = amount.replace(/,/g, '');
// this.amount = parseFloat(amount);
// this.detectChanges();
// }
// canWithdraw() {
// return (
// !this.hasWithdrawnToday &&
// !this.inProgress &&
// this.amount > 0 &&
// this.amount <= this.available
// );
// }
// async withdraw() {
// this.inProgress = true;
// this.error = '';
// this.detectChanges();
// try {
// await this.checkPreviousWithdrawals();
// await this.web3Wallet.ready();
// if (this.web3Wallet.isUnavailable()) {
// throw new Error('No Ethereum wallets available on your browser.');
// } else if (!(await this.web3Wallet.unlock())) {
// throw new Error(
// 'Your Ethereum wallet is locked or connected to another network.'
// );
// }
// let result: {
// address;
// guid;
// amount;
// gas;
// tx;
// } = await this.contract.request(
// this.session.getLoggedInUser().guid,
// this.amount * Math.pow(10, 18)
// );
// let response: any = await this.client.post(
// `api/v2/blockchain/transactions/withdraw`,
// result
// );
// if (response.done) {
// this.refresh();
// this.ledgerComponent.prepend(response.entity);
// } else {
// this.error = 'Server error';
// }
// } catch (e) {
// console.error(e);
// this.error = (e && e.message) || 'Server error';
// } finally {
// this.inProgress = false;
// this.detectChanges();
// }
// }
// refresh() {
// this.load();
// }
// detectChanges() {
// this.cd.markForCheck();
// this.cd.detectChanges();
// }
// }
This diff is collapsed.
src/app/modules/wallet/v2/phone-verification/phone-verification.component.html
0 → 100644
View file @
f4b79682
<div
class=
"m-walletModal__title"
>
Phone Verification
</div>
<div
class=
"m-walletModal__desc"
>
<p>
You can earn tokens for your contributions to the Minds network. The more
interactions on your content, the greater your share of the daily token
reward pool to your off-chain address.
</p>
<p>
To start earning rewards, you will need to enter a unique phone number.
</p>
</div>
<!-- TODOOJM: ensure the three options to trigger onSubmit() don't double-trigger the fx -->
<form
[formGroup]=
"form"
(ngSubmit)=
"onSubmit()"
(keyup.enter)=
"onSubmit()"
>
<div
class=
"m-walletForm__wrapper"
>
<div
class=
"m-walletForm__fieldsContainer"
>
<div
class=
"m-walletForm__field--text stretchedField"
*ngIf=
"!confirming"
>
<div
class=
"m-walletForm__row--label"
>
<label
for=
"number"
i18n
>
Mobile Phone Number
</label>
<m-tooltip
icon=
"help"
>
<ng-container
i18n
>
Placeholder...probs something about no voip numbers
allowed?
</ng-container
>
</m-tooltip>
</div>
<m-phone-input
formControlName=
"number"
class=
"m-walletForm__row--input"
[ngClass]=
"{ invalid: invalidNumber }"
name=
"number"
id=
"number"
ngDefaultControl
></m-phone-input>
<div
class=
"m-walletForm__row--validation"
>
<p
*ngIf=
"invalidNumber"
>
Invalid phone number
</p>
</div>
</div>
<div
class=
"m-walletForm__field--text stretchedField"
*ngIf=
"confirming"
>
<div
class=
"m-walletForm__row--label"
>
<label
for=
"code"
i18n
>
Verification Code
</label>
<m-tooltip
icon=
"help"
>
<ng-container
i18n
>
Placeholder
</ng-container>
</m-tooltip>
</div>
<div
class=
"m-walletForm__row--input"
[ngClass]=
"{ invalid: invalidCode }"
>
<input
type=
"text"
id=
"code"
name=
"code"
formControlName=
"code"
class=
"form-control"
autofocus
/>
</div>
<div
class=
"m-walletForm__row--validation"
>
<p
*ngIf=
"invalidCode"
>
Invalid verification code
</p>
</div>
</div>
</div>
<!-- TODOOJM button disabling -->
<!-- [disabled]="inProgress || invalidNumber || invalidCode" -->
<m-shadowboxSubmitButton
[disabled]=
"inProgress"
[saving]=
"inProgress"
(click)=
"onSubmit()"
>
{{ !confirming ? 'Send Verification' : 'Verify Code' }}
</m-shadowboxSubmitButton>
</div>
</form>
<div
class=
"m-walletModal__footnote--privacy"
*ngIf=
"!confirming"
>
Note: Minds does not store the phone numbers you provide. The numbers are
hashed using SHA-256 and combined with a salt key for privacy and security
purposes.
</div>
<div
class=
"m-walletModal__footnote--formStatus"
*ngIf=
"confirming"
>
<div
class=
"m-walletPhoneVerification__formStatusCodeSent"
>
Verification code sent to +{{ form.value.number }}
</div>
<div
class=
"m-walletPhoneVerification__formStatusActions"
>
Didn't receive it?
<a
(click)=
"validateNumber()"
>
Send it again
</a>
or
<a
(click)=
"changePhone()"
>
change phone number
</a>
</div>
</div>
<!-- <m-formToast></m-formToast> -->
This diff is collapsed.
src/app/modules/wallet/v2/phone-verification/phone-verification.component.scss
0 → 100644
View file @
f4b79682
m-walletPhoneVerification
{
.m-walletModal__footnote--privacy
{
margin-top
:
10px
;
font-size
:
13px
;
line-height
:
18px
;
}
.m-walletModal__footnote--formStatus
{
.m-walletPhoneVerification__formStatusCodeSent
{
margin-bottom
:
6px
;
@include
m-theme
()
{
color
:
themed
(
$m-grey-800
);
}
}
}
m-shadowboxSubmitButton
{
width
:
147px
;
button
{
width
:
100%
;
}
}
@media
screen
and
(
max-width
:
771px
)
{
m-shadowboxSubmitButton
{
margin
:
0
0
21px
0
;
}
.stretchedField
{
.m-walletForm__row--label
m-tooltip
{
.m-tooltip--bubble
{
right
:
12px
;
}
}
[
class
*=
'm-walletForm__row'
]
{
flex-flow
:
row
wrap
;
label
,
input
{
flex
:
1
1
100%
;
min-width
:
100%
;
max-width
:
100%
;
}
}
}
}
}
This diff is collapsed.
src/app/modules/wallet/v2/phone-verification/phone-verification.component.ts
0 → 100644
View file @
f4b79682
import
{
Component
,
OnInit
,
Input
,
Output
,
EventEmitter
,
ChangeDetectionStrategy
,
ChangeDetectorRef
,
}
from
'
@angular/core
'
;
import
{
FormBuilder
,
AbstractControl
,
FormGroup
,
FormControl
,
}
from
'
@angular/forms
'
;
import
{
FormToastService
}
from
'
../../../../common/services/form-toast.service
'
;
import
{
Client
}
from
'
../../../../services/api
'
;
import
{
Session
}
from
'
../../../../services/session
'
;
@
Component
({
selector
:
'
m-walletPhoneVerification
'
,
templateUrl
:
'
./phone-verification.component.html
'
,
changeDetection
:
ChangeDetectionStrategy
.
OnPush
,
})
export
class
WalletPhoneVerificationComponent
implements
OnInit
{
inProgress
=
false
;
confirming
=
false
;
invalidNumber
=
false
;
invalidCode
=
false
;
form
=
this
.
fb
.
group
({
number
:
[
''
],
code
:
[
''
],
secret
:
[
''
],
});
@
Output
()
phoneVerificationComplete
:
EventEmitter
<
any
>
=
new
EventEmitter
();
constructor
(
protected
session
:
Session
,
private
formToastService
:
FormToastService
,
private
fb
:
FormBuilder
,
protected
client
:
Client
,
protected
cd
:
ChangeDetectorRef
)
{}
ngOnInit
()
{}
async
validateNumber
()
{
this
.
invalidNumber
=
false
;
this
.
invalidCode
=
false
;
this
.
inProgress
=
true
;
this
.
detectChanges
();
try
{
const
response
:
any
=
await
this
.
client
.
post
(
'
api/v2/blockchain/rewards/verify
'
,
{
number
:
this
.
form
.
value
.
number
,
}
);
this
.
form
.
controls
[
'
secret
'
].
setValue
(
response
.
secret
);
this
.
confirming
=
true
;
}
catch
(
e
)
{
this
.
invalidNumber
=
true
;
// this.formToastService.error(e.message);
console
.
error
(
e
.
message
);
}
this
.
inProgress
=
false
;
this
.
detectChanges
();
}
async
confirmCode
()
{
this
.
invalidNumber
=
false
;
this
.
invalidCode
=
false
;
this
.
inProgress
=
true
;
this
.
detectChanges
();
try
{
const
response
:
any
=
await
this
.
client
.
post
(
'
api/v2/blockchain/rewards/confirm
'
,
{
number
:
this
.
form
.
value
.
number
,
code
:
this
.
form
.
value
.
code
,
secret
:
this
.
form
.
value
.
secret
,
}
);
window
.
Minds
.
user
.
rewards
=
true
;
this
.
phoneVerificationComplete
.
emit
();
}
catch
(
e
)
{
this
.
invalidCode
=
true
;
// this.formToastService.error(e.message);
}
this
.
inProgress
=
false
;
this
.
detectChanges
();
}
changePhone
()
{
this
.
form
.
reset
();
console
.
log
(
this
.
form
.
value
);
this
.
invalidNumber
=
false
;
this
.
invalidCode
=
false
;
this
.
confirming
=
false
;
this
.
detectChanges
();
}
onSubmit
()
{
this
.
confirming
?
this
.
confirmCode
()
:
this
.
validateNumber
();
}
detectChanges
()
{
this
.
cd
.
markForCheck
();
this
.
cd
.
detectChanges
();
}
}
This diff is collapsed.
src/app/modules/wallet/v2/settings-btc/settings-btc.component.html
View file @
f4b79682
<
p
>
TODO: m-walletSettings--btc
</
p
>
<
div
class=
"m-walletSettings"
>
<p>
🚧 m-walletSettings--btc 🚧
</p>
</
div
>
This diff is collapsed.
src/app/modules/wallet/v2/settings-eth/settings-eth.component.html
View file @
f4b79682
<p>
TODO: m-walletSettings--eth
</p>
<div
class=
"m-walletSettings"
>
<h2>
Ether Address
</h2>
<p>
🚧 WIP! See
<a
href=
"https://gitlab.com/minds/ux-design/ux/issues/26"
target=
"_blank"
>
UX issue #26
</a
>
🚧
</p>
<p>
Your Ether address is the same as your on-chain address.
<m-tooltip
icon=
"help"
>
<ng-container
i18n
>
🚧 Placeholder: Why? On-chain tokens run on the Ethereum network and
require Ether to send 🚧
</ng-container
>
</m-tooltip>
</p>
<p></p>
<p>
To view or change your address, go to
<a
click=
"scrollToTokenSettings())"
>
token settings
</a>
.
</p>
</div>
This diff is collapsed.
src/app/modules/wallet/v2/settings-eth/settings-eth.component.ts
View file @
f4b79682
import
{
Component
,
OnInit
}
from
'
@angular/core
'
;
import
{
Component
,
OnInit
,
Output
,
EventEmitter
}
from
'
@angular/core
'
;
@
Component
({
selector
:
'
m-walletSettings--eth
'
,
templateUrl
:
'
./settings-eth.component.html
'
,
})
export
class
WalletSettingsETHComponent
implements
OnInit
{
@
Output
()
showTokenSettings
:
EventEmitter
<
any
>
=
new
EventEmitter
();
constructor
()
{}
ngOnInit
()
{}
scrollToSettings
()
{
const
settingsEl
=
document
.
getElementById
(
'
tokenSettings
'
);
if
(
!
settingsEl
)
{
this
.
showTokenSettings
.
emit
();
}
setTimeout
(
()
=>
document
.
getElementById
(
'
dashboardViewsTabs
'
).
scrollIntoView
({
behavior
:
'
smooth
'
,
}),
0
);
}
}
This diff is collapsed.
src/app/modules/wallet/v2/settings-tokens/settings-tokens.component.html
View file @
f4b79682
<p>
TODO: m-walletSettings--tokens
</p>
<div
class=
"m-walletSettings"
id=
"tokenSettings"
>
<div
class=
"m-walletSettingsView--setup"
*ngIf=
"!display"
>
<h4>
On-Chain address
</h4>
<div
class=
"m-walletSettings__setupOptions__recommendation"
>
<i
class=
"material-icons"
>
thumb_up
</i><span>
RECOMMENDED
</span>
</div>
<ul
class=
"m-walletSettingsView__setupOptions__container"
>
<li
class=
"m-walletSettingsView__setupOption--metamask"
>
<div>
<img
class=
"metamask"
[src]=
"minds.cdn_assets_url + 'assets/ext/metamask.png'"
/>
<h2>
MetaMask
</h2>
</div>
<p>
<a
href=
"https://metamask.io/"
target=
"_blank"
>
Install MetaMask
</a>
for the most seamless user experience.
</p>
<m-shadowboxSubmitButton
[disabled]=
"inProgress"
[saving]=
"inProgress"
(click)=
"display = Views.UseExternal; useExternal()"
>
Link MetaMask
</m-shadowboxSubmitButton>
</li>
<li
class=
"m-walletSettingsView__setupOption--custom"
>
<h2>
Custom
</h2>
<p>
You don’t need to use MetaMask. You can alternatively manage your own
address.
</p>
<div>
<a
(click)=
"display = Views.CreateAddress; createAddress()"
>
Create a new address
</a
>
<span>
or
</span>
<a
(click)=
"display = Views.ProvideAddress"
>
Use your private key
</a>
</div>
</li>
<p
*ngIf=
""
>
<a
(click)=
"display = Views.currentAddress"
>
🚧 Current On-Chain Address 🚧
</a
>
</p>
</ul>
</div>
<ul
*ngIf=
"display"
>
<!---CUSTOM - CREATE ADDRESS----------------------------------------->
<li
class=
"m-walletSettingsView--addressCreate"
*ngIf=
"display === Views.CreateAddress"
>
<h2>
Create Address
</h2>
<p
*ngIf=
"!generatedAccount"
>
Generating address ...
<span
*ngIf=
"inProgress && !generatedAccount"
class=
"mdl-spinner mdl-js-spinner is-active"
[
mdl
]
></span>
</p>
<p
*ngIf=
"generatedAccount"
>
The address
<span
class=
"m-walletSettings__address--emphasis"
>
{{
generatedAccount.address
}}
</span>
was successully saved as your on-chain address. Clicking the button
below will download its private key. Ensure you safely store the private
key file.
</p>
<m-shadowboxSubmitButton
[disabled]=
"!generatedAccount"
[saving]=
"inProgress && generatedAccount"
(click)=
"downloadPrivateKey()"
>
Download Private Key
</m-shadowboxSubmitButton>
<a
class=
"m-walletSettings__backButton"
(click)=
"display = null"
><i
class=
"material-icons"
>
arrow_back
</i><span>
Back
</span></a
>
</li>
<!---CUSTOM - PROVIDE ADDRESS---------------------------->
<li
class=
"m-walletSettingsView--addressProvide"
*ngIf=
"display === Views.ProvideAddress"
>
<h2>
Provide Address
</h2>
<p>
Enter the address that will be stored as your wallet for Minds on-chain
tokens and Ether payments. Remember that you will need your wallet's
private key to conduct transactions.
</p>
<div
class=
"m-walletForm__field--text stretchedField"
>
<div
class=
"m-walletForm__row--label"
>
<label
for=
"providedAddress"
i18n
>
On-chain Address
</label>
<m-tooltip
icon=
"help"
>
<ng-container
i18n
>
This address is where you will receive on-chain Minds tokens and
Ether payments
</ng-container
>
</m-tooltip>
</div>
<div
class=
"m-walletForm__row--input"
>
<input
type=
"text"
id=
"providedAddress"
name=
"providedAddress"
class=
"form-control"
[readonly]=
"inProgress"
[(ngModel)]=
"providedAddress"
/>
</div>
</div>
<m-shadowboxSubmitButton
[disabled]=
"inProgress || !providedAddress"
[saving]=
"inProgress"
(click)=
"provideAddress()"
>
Save Address
</m-shadowboxSubmitButton>
<a
class=
"m-walletSettings__backButton"
(click)=
"display = null"
><i
class=
"material-icons"
>
arrow_back
</i><span>
Back
</span></a
>
</li>
<!---USE EXTERNAL ADDRESS----------------------------------------------->
<li
class=
"m-walletSettingsView--addressExternal"
*ngIf=
"display === Views.UseExternal"
>
<p>
🚧 lol 🦊 see
<a
href=
"https://gitlab.com/minds/ux-design/ux/issues/27"
target=
"_blank"
>
UX issue #27
</a
>
🚧
</p>
<img
class=
"metamask"
[src]=
"minds.cdn_assets_url + 'assets/ext/metamask.png'"
/>
<h2>
MetaMask
</h2>
<p>
<ng-container>
Please ensure you select the
<b>
Main Ethereum Network
</b>
.
</ng-container>
<ng-container
*ngIf=
"downloadingMetamask"
>
<b>
Note: After installing and setting up MetaMask you might need to
reload Minds.
</b>
</ng-container>
</p>
<div
class=
"m-walletSettings--tokens--buttons"
*ngIf=
"!hasExternal"
>
<button
(click)=
"downloadMetamask()"
>
Download MetaMask
</button>
</div>
<div
class=
"m-walletSettings--tokens--buttons"
*ngIf=
"hasExternal"
>
<span
class=
"m-walletSettings--tokens--buttons-input"
>
<ng-container
*ngIf=
"providedAddress; else noProvidedAddress"
>
{{ providedAddress }}
</ng-container>
<ng-template
#noProvidedAddress
>
MetaMask is either locked or connected to another network.
</ng-template>
</span>
</div>
<a
class=
"m-walletSettings__backButton"
(click)=
"display = null"
><i
class=
"material-icons"
>
arrow_back
</i><span>
Back
</span></a
>
</li>
<!---CURRENT ADDRESS ----------------------------------------------->
<li
class=
"m-walletSettingsView--addressCurrent"
*ngIf=
"display === Views.currentAddress"
>
<h2>
On-Chain Address
</h2>
<p
style=
"margin-bottom: 24px"
>
🚧 WIP! See
<a
href=
"https://gitlab.com/minds/ux-design/ux/issues/18"
target=
"_blank"
>
UX issue #18
</a
>
🚧
</p>
<div
class=
"m-walletForm__field--text stretchedField"
>
<div
class=
"m-walletForm__row--label"
>
<label
for=
"currentAddress"
i18n
>
Address
</label>
<m-tooltip
icon=
"help"
>
<ng-container
i18n
>
placeholder: 🚧 This will eventually not be an input field
🚧
</ng-container
>
</m-tooltip>
</div>
<div
class=
"m-walletForm__row--input"
>
<input
type=
"text"
id=
"currentAddress"
name=
"currentAddress"
class=
"form-control"
readonly
[(ngModel)]=
"currentAddress"
/>
</div>
</div>
<p><a
(click)=
"display = null"
>
Change Address
</a></p>
</li>
</ul>
</div>
<m-formToast></m-formToast>
This diff is collapsed.
src/app/modules/wallet/v2/settings-tokens/settings-tokens.component.ts
View file @
f4b79682
import
{
Component
,
OnInit
}
from
'
@angular/core
'
;
import
{
ChangeDetectionStrategy
,
ChangeDetectorRef
,
Component
,
OnInit
,
OnDestroy
,
Input
,
Output
,
EventEmitter
,
}
from
'
@angular/core
'
;
import
{
Router
}
from
'
@angular/router
'
;
import
{
Client
}
from
'
../../../../services/api/client
'
;
import
{
Session
}
from
'
../../../../services/session
'
;
import
{
LocalWalletService
}
from
'
../../../blockchain/local-wallet.service
'
;
import
{
BlockchainService
}
from
'
../../../blockchain/blockchain.service
'
;
import
{
Web3WalletService
}
from
'
../../../blockchain/web3-wallet.service
'
;
import
{
getBrowser
}
from
'
../../../../utils/browser
'
;
import
{
FormToastService
}
from
'
../../../../common/services/form-toast.service
'
;
enum
Views
{
CreateAddress
=
1
,
ProvideAddress
,
UseExternal
,
currentAddress
,
}
@
Component
({
selector
:
'
m-walletSettings--tokens
'
,
templateUrl
:
'
./settings-tokens.component.html
'
,
changeDetection
:
ChangeDetectionStrategy
.
OnPush
,
})
export
class
WalletSettingsTokensComponent
implements
OnInit
{
constructor
()
{}
export
class
WalletSettingsTokensComponent
implements
OnInit
,
OnDestroy
{
@
Input
()
wallet
;
@
Input
()
skippable
:
boolean
=
true
;
@
Output
()
addressSetupComplete
:
EventEmitter
<
any
>
=
new
EventEmitter
();
inProgress
:
boolean
=
false
;
error
:
string
;
display
:
Views
;
generatedAccount
:
any
;
providedAddress
:
string
=
''
;
hasExternal
:
boolean
=
false
;
currentAddress
:
string
=
''
;
downloadingMetamask
:
boolean
=
false
;
minds
=
window
.
Minds
;
readonly
Views
=
Views
;
private
_externalTimer
;
constructor
(
protected
client
:
Client
,
protected
cd
:
ChangeDetectorRef
,
protected
session
:
Session
,
protected
router
:
Router
,
protected
localWallet
:
LocalWalletService
,
protected
blockchain
:
BlockchainService
,
protected
web3Wallet
:
Web3WalletService
,
private
formToastService
:
FormToastService
)
{}
ngOnInit
()
{
//already has an address
const
currentAddress
=
this
.
session
.
getLoggedInUser
().
eth_wallet
;
this
.
currentAddress
=
currentAddress
||
this
.
wallet
.
receiver
.
address
;
if
(
this
.
currentAddress
)
{
this
.
display
=
Views
.
currentAddress
;
this
.
addressSetupComplete
.
emit
();
}
this
.
checkExternal
();
}
ngOnDestroy
()
{
if
(
this
.
_externalTimer
)
{
clearInterval
(
this
.
_externalTimer
);
}
}
async
checkExternal
()
{
this
.
hasExternal
=
!
(
await
this
.
web3Wallet
.
isLocal
());
this
.
detectChanges
();
}
async
createAddress
()
{
try
{
this
.
inProgress
=
true
;
this
.
detectChanges
();
this
.
generatedAccount
=
await
this
.
localWallet
.
create
(
false
);
await
this
.
blockchain
.
setWallet
({
address
:
this
.
generatedAccount
.
address
,
});
}
catch
(
e
)
{
console
.
error
(
e
);
this
.
formToastService
.
error
(
e
);
}
finally
{
this
.
inProgress
=
false
;
this
.
detectChanges
();
}
}
async
downloadPrivateKey
()
{
try
{
this
.
inProgress
=
true
;
this
.
detectChanges
();
const
{
address
,
privateKey
}
=
this
.
generatedAccount
,
filename
=
`pk_
${
address
}
.csv`
,
blob
=
new
Blob
([
privateKey
],
{
type
:
'
text/csv
'
});
if
(
window
.
navigator
.
msSaveOrOpenBlob
)
{
window
.
navigator
.
msSaveBlob
(
blob
,
filename
);
this
.
inProgress
=
false
;
// TODOOJM
this
.
addressSetupComplete
.
emit
();
}
else
{
const
link
=
window
.
document
.
createElement
(
'
a
'
),
objectUrl
=
window
.
URL
.
createObjectURL
(
blob
);
link
.
href
=
objectUrl
;
link
.
download
=
filename
;
document
.
body
.
appendChild
(
link
);
link
.
click
();
document
.
body
.
removeChild
(
link
);
setTimeout
(()
=>
{
URL
.
revokeObjectURL
(
objectUrl
);
this
.
generatedAccount
=
null
;
// this.addressSetupComplete.emit(); //TODOOJM
this
.
inProgress
=
false
;
// TODOOJM
},
1000
);
}
}
catch
(
e
)
{
console
.
error
(
e
);
this
.
formToastService
.
error
(
e
);
this
.
inProgress
=
false
;
}
}
canProvideAddress
()
{
return
(
this
.
providedAddress
&&
/^0x
[
a-fA-F0-9
]{40}
$/
.
test
(
this
.
providedAddress
)
);
}
async
provideAddress
()
{
if
(
!
this
.
canProvideAddress
()
||
this
.
inProgress
)
{
return
;
}
try
{
this
.
inProgress
=
true
;
this
.
detectChanges
();
await
this
.
blockchain
.
setWallet
({
address
:
this
.
providedAddress
});
this
.
addressSetupComplete
.
emit
();
}
catch
(
e
)
{
this
.
formToastService
.
error
(
e
);
console
.
error
(
e
);
}
finally
{
this
.
inProgress
=
false
;
this
.
detectChanges
();
}
}
downloadMetamask
()
{
let
browser
:
string
=
getBrowser
();
let
url
=
''
;
switch
(
browser
)
{
case
'
chrome
'
:
url
=
'
https://chrome.google.com/webstore/detail/metamask/nkbihfbeogaeaoehlefnkodbefgpgknn
'
;
case
'
firefox
'
:
url
=
'
https://addons.mozilla.org/firefox/addon/ether-metamask/
'
;
case
'
opera
'
:
url
=
'
https://addons.opera.com/extensions/details/metamask/
'
;
default
:
url
=
'
https://metamask.io
'
;
}
window
.
open
(
url
);
this
.
downloadingMetamask
=
true
;
}
async
useExternal
()
{
await
this
.
web3Wallet
.
ready
();
this
.
detectExternal
();
this
.
_externalTimer
=
setInterval
(()
=>
{
this
.
detectExternal
();
},
1000
);
}
async
detectExternal
()
{
const
address
:
string
=
(
await
this
.
web3Wallet
.
getCurrentWallet
(
true
))
||
''
;
if
(
this
.
providedAddress
!==
address
)
{
this
.
providedAddress
=
address
;
this
.
detectChanges
();
if
(
this
.
providedAddress
)
{
clearInterval
(
this
.
_externalTimer
);
this
.
provideAddress
();
}
}
}
ngOnInit
()
{}
detectChanges
()
{
this
.
cd
.
markForCheck
();
this
.
cd
.
detectChanges
();
}
}
This diff is collapsed.
src/app/modules/wallet/v2/settings-usd/settings-usd.component.html
View file @
f4b79682
<
p
>
TODO: m-walletSettings--usd
</
p
>
<
div
class=
"m-walletSettings"
>
🚧 m-walletSettings--usd 🚧
</
div
>
This diff is collapsed.
src/app/modules/wallet/v2/token-onboarding/token-onboarding.component.html
0 → 100644
View file @
f4b79682
<div
class=
"m-walletTokenOnboarding__stepsContainer"
>
<div
class=
"m-walletTokenOnboardingStep--verifyPhone"
>
<div
class=
"m-walletTokenOnboardingStep__title"
>
<span>
1.
</span>
<a
(click)=
"clickedPhoneStep()"
[ngClass]=
"{ phoneVerified: phoneVerified }"
>
Verify your phone number
</a
>
<i
class=
"material-icons"
*ngIf=
"phoneVerified"
>
check
</i>
</div>
<div
class=
"m-walletTokenOnboardingStep__desc"
>
Used simply to verify your uniqueness.
</div>
</div>
<div
class=
"m-walletTokenOnboardingStep--addAddress"
>
<div
class=
"m-walletTokenOnboardingStep__title"
>
<span>
2.
</span>
<a
(click)=
"clickedAddressStep()"
[ngClass]=
"{ disabled: !phoneVerified }"
>
Add your on-chain address
</a
>
</div>
<div
class=
"m-walletTokenOnboardingStep__desc"
>
Your Ethereum address allows you to start receiving payments on the
blockchain.
</div>
</div>
</div>
<m-walletModal
[showModal]=
"showModal"
(closeModal)=
"showModal = false"
>
<m-walletPhoneVerification
class=
"m-walletTokenOnboardingModal__view--verifyPhone"
*ngIf=
"activeStep === 'phone'"
(phoneVerificationComplete)=
"phoneVerificationComplete()"
>
</m-walletPhoneVerification>
</m-walletModal>
This diff is collapsed.
src/app/modules/wallet/v2/token-onboarding/token-onboarding.component.scss
0 → 100644
View file @
f4b79682
m-walletTokenOnboarding
{
display
:
block
;
font-size
:
14px
;
line-height
:
19px
;
margin-bottom
:
35px
;
font-weight
:
300
;
.m-walletTokenOnboarding__stepsContainer
{
display
:
flex
;
flex-flow
:
row
wrap
;
justify-content
:
space-between
;
border-radius
:
2px
;
@include
m-theme
()
{
border
:
1px
solid
themed
(
$m-grey-50
);
}
a
{
text-decoration
:
underline
;
cursor
:
pointer
;
display
:
inline-block
;
font-weight
:
400
;
&
.disabled
{
text-decoration
:
none
;
cursor
:
text
;
@include
m-theme
()
{
color
:
themed
(
$m-grey-800
);
}
}
}
}
[
class
*=
'm-walletTokenOnboardingStep--'
]
{
display
:
flex
;
flex-direction
:
column
;
padding
:
19px
27px
;
box-sizing
:
border-box
;
flex-basis
:
50%
;
min-width
:
200px
;
}
.m-walletTokenOnboardingStep--verifyPhone
{
@include
m-theme
()
{
border-right
:
1px
solid
themed
(
$m-grey-50
);
}
}
.m-walletTokenOnboardingStep__title
{
font-weight
:
500
;
display
:
flex
;
flex-flow
:
row
nowrap
;
align-items
:
center
;
@include
m-theme
()
{
color
:
themed
(
$m-grey-800
);
}
a
{
font-size
:
14px
;
line-height
:
19px
;
margin
:
0
8px
0
4px
;
&
.phoneVerified
{
cursor
:
default
;
text-decoration
:
line-through
;
@include
m-theme
()
{
color
:
themed
(
$m-grey-200
);
}
}
}
i
{
line-height
:
17px
;
@include
m-theme
()
{
color
:
themed
(
$m-green
);
}
}
}
.m-walletTokenOnboardingStep__desc
{
font-size
:
13px
;
line-height
:
18px
;
margin-top
:
6px
;
@include
m-theme
()
{
color
:
themed
(
$m-grey-600
);
}
}
// ***************************************************
@media
screen
and
(
max-width
:
$max-mobile
)
{
[
class
*=
'm-walletTokenOnboardingStep--'
]
{
padding
:
19px
;
}
}
@media
screen
and
(
max-width
:
830px
)
{
[
class
*=
'm-walletTokenOnboardingStep--'
]
{
flex-basis
:
100%
;
padding
:
14px
20px
;
}
.m-walletTokenOnboardingStep--verifyPhone
{
@include
m-theme
()
{
border-right-width
:
0px
;
border-bottom
:
1px
solid
themed
(
$m-grey-50
);
}
}
.m-walletTokenOnboardingStep__desc
{
padding-left
:
16px
;
}
}
}
This diff is collapsed.
src/app/modules/wallet/v2/token-onboarding/token-onboarding.component.ts
0 → 100644
View file @
f4b79682
import
{
Component
,
OnInit
,
Input
,
Output
,
EventEmitter
,
ChangeDetectionStrategy
,
ChangeDetectorRef
,
}
from
'
@angular/core
'
;
import
{
Router
,
ActivatedRoute
}
from
'
@angular/router
'
;
import
{
Session
}
from
'
../../../../services/session
'
;
import
{
FormToastService
}
from
'
../../../../common/services/form-toast.service
'
;
@
Component
({
selector
:
'
m-walletTokenOnboarding
'
,
templateUrl
:
'
./token-onboarding.component.html
'
,
changeDetection
:
ChangeDetectionStrategy
.
OnPush
,
})
export
class
WalletTokenOnboardingComponent
implements
OnInit
{
phoneVerified
=
false
;
addressAdded
=
false
;
showModal
=
false
;
activeStep
=
'
phone
'
;
// || address
@
Output
()
onboardingComplete
:
EventEmitter
<
any
>
=
new
EventEmitter
();
@
Output
()
showTokenSettings
:
EventEmitter
<
any
>
=
new
EventEmitter
();
constructor
(
protected
session
:
Session
,
protected
cd
:
ChangeDetectorRef
,
private
formToastService
:
FormToastService
,
protected
router
:
Router
,
private
route
:
ActivatedRoute
)
{}
ngOnInit
()
{
this
.
phoneVerified
=
this
.
session
.
getLoggedInUser
().
rewards
;
this
.
addressAdded
=
this
.
session
.
getLoggedInUser
().
eth_wallet
;
if
(
this
.
phoneVerified
&&
this
.
addressAdded
)
{
this
.
onboardingComplete
.
emit
();
}
this
.
detectChanges
();
}
clickedPhoneStep
()
{
if
(
!
this
.
phoneVerified
)
{
this
.
activeStep
=
'
phone
'
;
this
.
showModal
=
true
;
}
this
.
detectChanges
();
}
clickedAddressStep
()
{
if
(
!
this
.
addressAdded
)
{
this
.
activeStep
=
'
address
'
;
this
.
scrollToSettings
();
}
this
.
detectChanges
();
}
scrollToSettings
()
{
const
settingsEl
=
document
.
getElementById
(
'
tokenSettings
'
);
if
(
!
settingsEl
)
{
this
.
showTokenSettings
.
emit
();
}
setTimeout
(
()
=>
document
.
getElementById
(
'
dashboardViewsTabs
'
).
scrollIntoView
({
behavior
:
'
smooth
'
,
}),
0
);
}
phoneVerificationComplete
()
{
this
.
phoneVerified
=
true
;
this
.
showModal
=
false
;
this
.
formToastService
.
success
(
'
Your phone number has been verified
'
);
if
(
!
this
.
addressAdded
)
{
this
.
activeStep
=
'
address
'
;
}
else
{
this
.
onboardingComplete
.
emit
();
}
}
addressSetupComplete
()
{
this
.
addressAdded
=
true
;
this
.
showModal
=
false
;
if
(
!
this
.
phoneVerified
)
{
this
.
activeStep
=
'
phone
'
;
}
else
{
this
.
onboardingComplete
.
emit
();
}
}
detectChanges
()
{
this
.
cd
.
markForCheck
();
this
.
cd
.
detectChanges
();
}
}
This diff is collapsed.
src/app/modules/wallet/v2/transactions-table/transactions-table.component.html
View file @
f4b79682
<p>
TODO: m-walletTransactionsTable
🚧 m-walletTransactionsTable 🚧
</p>
This diff is collapsed.
src/app/modules/wallet/wallet.module.ts
View file @
f4b79682
...
...
@@ -53,13 +53,16 @@ import { WalletDashboardComponent } from './v2/dashboard.component';
import
{
WalletBalanceTokensV2Component
}
from
'
./v2/balance-tokens/balance-tokens.component
'
;
import
{
WalletChartComponent
}
from
'
./v2/chart/chart.component
'
;
import
{
WalletTransactionsTableComponent
}
from
'
./v2/transactions-table/transactions-table.component
'
;
import
{
WalletActionButtonComponent
}
from
'
./v2/action-button/action-button.component
'
;
import
{
WalletRewardsPopupComponent
}
from
'
./v2/rewards-popup/rewards-popup.component
'
;
import
{
WalletDashboardService
}
from
'
./v2/dashboard.service
'
;
import
{
WalletSettingsTokensComponent
}
from
'
./v2/settings-tokens/settings-tokens.component
'
;
import
{
WalletSettingsUSDComponent
}
from
'
./v2/settings-usd/settings-usd.component
'
;
import
{
WalletSettingsETHComponent
}
from
'
./v2/settings-eth/settings-eth.component
'
;
import
{
WalletSettingsBTCComponent
}
from
'
./v2/settings-btc/settings-btc.component
'
;
import
{
WalletTokenOnboardingComponent
}
from
'
./v2/token-onboarding/token-onboarding.component
'
;
import
{
WalletModalComponent
}
from
'
./v2/modal/modal.component
'
;
import
{
WalletPhoneVerificationComponent
}
from
'
./v2/phone-verification/phone-verification.component
'
;
import
{
WalletOnchainTransferComponent
}
from
'
./v2/onchain-transfer/onchain-transfer.component
'
;
const
walletRoutes
:
Routes
=
[
{
...
...
@@ -174,13 +177,16 @@ const walletRoutes: Routes = [
WalletDashboardComponent
,
WalletBalanceTokensV2Component
,
WalletChartComponent
,
WalletActionButtonComponent
,
WalletRewardsPopupComponent
,
WalletTransactionsTableComponent
,
WalletSettingsTokensComponent
,
WalletSettingsUSDComponent
,
WalletSettingsETHComponent
,
WalletSettingsBTCComponent
,
WalletTokenOnboardingComponent
,
WalletModalComponent
,
WalletPhoneVerificationComponent
,
WalletOnchainTransferComponent
,
],
exports
:
[
WalletComponent
,
...
...
This diff is collapsed.
src/typings/minds.d.ts
View file @
f4b79682
...
...
@@ -39,6 +39,7 @@ interface Minds {
};
};
contribution_values
:
{
[
key
:
string
]:
number
};
from_email_confirmation
?:
boolean
;
}
interface
MindsNavigation
{
...
...
This diff is collapsed.