Added closed investment rendering
This commit is contained in:
parent
4ad8fdbc2f
commit
1ffb70858c
214
css/main.css
214
css/main.css
@ -18,30 +18,41 @@ body {
|
|||||||
body {
|
body {
|
||||||
--accent-color: #2353ff;
|
--accent-color: #2353ff;
|
||||||
--light-shade: rgba(var(--text-color), 0.06);
|
--light-shade: rgba(var(--text-color), 0.06);
|
||||||
--text-color: 17, 17, 17;
|
--text-color: 20, 20, 20;
|
||||||
--text-color-light: 100, 100, 100;
|
--foreground-color: 252, 253, 255;
|
||||||
--foreground-color: 255, 255, 255;
|
--background-color: 241, 243, 248;
|
||||||
--background-color: #f6f6f6;
|
--danger-color: rgb(255, 75, 75);
|
||||||
--error-color: red;
|
--green: #1cad59;
|
||||||
--green: #00843b;
|
--yellow: rgb(220, 165, 0);
|
||||||
color: rgba(var(--text-color), 1);
|
color: rgba(var(--text-color), 1);
|
||||||
background: var(--background-color);
|
background: rgba(var(--background-color), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
body[data-theme=dark] {
|
body[data-theme=dark] {
|
||||||
--accent-color: #2353ff;
|
--accent-color: #2353ff;
|
||||||
--green: #13ff5a;
|
--text-color: 200, 200, 200;
|
||||||
--text-color: 240, 240, 240;
|
--foreground-color: 27, 28, 29;
|
||||||
--text-color-light: 170, 170, 170;
|
--background-color: 21, 22, 22;
|
||||||
--foreground-color: 20, 20, 20;
|
--danger-color: rgb(255, 106, 106);
|
||||||
--background-color: #0a0a0a;
|
--green: #00e676;
|
||||||
--error-color: rgb(255, 106, 106);
|
--yellow: rgb(255, 213, 5);
|
||||||
}
|
}
|
||||||
body[data-theme=dark] ::-webkit-calendar-picker-indicator {
|
body[data-theme=dark] ::-webkit-calendar-picker-indicator {
|
||||||
filter: invert(1);
|
filter: invert(1);
|
||||||
}
|
}
|
||||||
body[data-theme=dark] sm-input.outlined {
|
body[data-theme=dark] a:-webkit-any-link {
|
||||||
--active-placeholder-color: rgba(var(--text-color), 1);
|
filter: saturate(0.5) brightness(2);
|
||||||
|
}
|
||||||
|
body[data-theme=dark] a:-moz-any-link {
|
||||||
|
filter: saturate(0.5) brightness(2);
|
||||||
|
}
|
||||||
|
body[data-theme=dark] a:any-link {
|
||||||
|
filter: saturate(0.5) brightness(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.overpass {
|
||||||
|
font-family: "Overpass", sans-serif;
|
||||||
|
font-weight: 700;
|
||||||
}
|
}
|
||||||
|
|
||||||
.h1 {
|
.h1 {
|
||||||
@ -54,6 +65,8 @@ body[data-theme=dark] sm-input.outlined {
|
|||||||
|
|
||||||
.h3 {
|
.h3 {
|
||||||
font-size: 3rem;
|
font-size: 3rem;
|
||||||
|
line-height: 1.1;
|
||||||
|
letter-spacing: -0.02em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.h4 {
|
.h4 {
|
||||||
@ -185,6 +198,13 @@ button:disabled {
|
|||||||
opacity: 0.5;
|
opacity: 0.5;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.cta {
|
||||||
|
text-transform: uppercase;
|
||||||
|
font-weight: 700;
|
||||||
|
letter-spacing: 0.05em;
|
||||||
|
padding: 0.8rem 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
a:-webkit-any-link {
|
a:-webkit-any-link {
|
||||||
position: relative;
|
position: relative;
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
@ -257,6 +277,37 @@ a:any-link:focus-visible {
|
|||||||
fill: rgba(var(--text-color), 1);
|
fill: rgba(var(--text-color), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.multi-state-button {
|
||||||
|
display: grid;
|
||||||
|
text-align: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.multi-state-button > * {
|
||||||
|
grid-area: 1/1/2/2;
|
||||||
|
}
|
||||||
|
.multi-state-button button {
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
.multi-state-button sm-spinner {
|
||||||
|
justify-self: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
sm-spinner {
|
||||||
|
--size: 1.5rem;
|
||||||
|
--stroke-width: 0.1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.password-field label {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
.password-field label input:checked ~ .visible {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.password-field label input:not(:checked) ~ .invisible {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
sm-input,
|
sm-input,
|
||||||
sm-textarea {
|
sm-textarea {
|
||||||
--border-radius: 0.5rem;
|
--border-radius: 0.5rem;
|
||||||
@ -452,14 +503,10 @@ ul {
|
|||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.hide-completely {
|
.hidden {
|
||||||
display: none !important;
|
display: none !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.no-transformations {
|
|
||||||
transform: none !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.overflow-ellipsis {
|
.overflow-ellipsis {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
@ -501,6 +548,15 @@ ul {
|
|||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.popup__header {
|
||||||
|
display: grid;
|
||||||
|
gap: 0.5rem;
|
||||||
|
width: 100%;
|
||||||
|
padding: 0 1.5rem 0 0.5rem;
|
||||||
|
align-items: center;
|
||||||
|
grid-template-columns: auto 1fr auto;
|
||||||
|
}
|
||||||
|
|
||||||
#loading_page,
|
#loading_page,
|
||||||
#error_page {
|
#error_page {
|
||||||
position: relative;
|
position: relative;
|
||||||
@ -677,20 +733,15 @@ ul {
|
|||||||
|
|
||||||
#main_header__logo {
|
#main_header__logo {
|
||||||
fill: white;
|
fill: white;
|
||||||
height: 2.4rem;
|
height: 1.5rem;
|
||||||
width: 2.4rem;
|
width: 1.5rem;
|
||||||
margin-left: -0.3rem;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.header__company-name {
|
.header__company-name {
|
||||||
|
font-size: 1em;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
}
|
}
|
||||||
|
|
||||||
.header__app-name {
|
|
||||||
font-weight: 700;
|
|
||||||
font-size: 1.2rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
#current_price {
|
#current_price {
|
||||||
justify-self: flex-start;
|
justify-self: flex-start;
|
||||||
}
|
}
|
||||||
@ -760,7 +811,7 @@ ul {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#home_page {
|
#home_page {
|
||||||
--side-padding: 5vw;
|
--side-padding: 1rem;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
padding: 0 max(1rem, var(--side-padding));
|
padding: 0 max(1rem, var(--side-padding));
|
||||||
@ -769,7 +820,7 @@ ul {
|
|||||||
|
|
||||||
#homepage__hero-section {
|
#homepage__hero-section {
|
||||||
color: white;
|
color: white;
|
||||||
padding: 2rem 0 12rem 0;
|
padding: 2rem var(--side-padding) 9rem var(--side-padding);
|
||||||
margin: 0 calc(-1 * max(1rem, var(--side-padding))) -5.5rem calc(-1 * max(1rem, var(--side-padding)));
|
margin: 0 calc(-1 * max(1rem, var(--side-padding))) -5.5rem calc(-1 * max(1rem, var(--side-padding)));
|
||||||
background-image: url(../assets/bg-1.svg);
|
background-image: url(../assets/bg-1.svg);
|
||||||
background-color: var(--accent-color);
|
background-color: var(--accent-color);
|
||||||
@ -779,6 +830,12 @@ ul {
|
|||||||
color: rgba(255, 255, 255, 0.8);
|
color: rgba(255, 255, 255, 0.8);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#refresh_button {
|
||||||
|
color: var(--accent-color);
|
||||||
|
background-color: white;
|
||||||
|
border: solid thin rgba(0, 0, 0, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
.fund-list__header {
|
.fund-list__header {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@ -834,7 +891,7 @@ ul {
|
|||||||
#fund_list {
|
#fund_list {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 1.5rem;
|
gap: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
#fund_list__empty-state {
|
#fund_list__empty-state {
|
||||||
@ -952,6 +1009,9 @@ form select option {
|
|||||||
border-radius: 0.5rem;
|
border-radius: 0.5rem;
|
||||||
border: solid thin rgba(var(--text-color), 0.2);
|
border: solid thin rgba(var(--text-color), 0.2);
|
||||||
}
|
}
|
||||||
|
.fund-investor > .grid:first-of-type {
|
||||||
|
width: min(40ch, 100%);
|
||||||
|
}
|
||||||
.fund-investor__redeem {
|
.fund-investor__redeem {
|
||||||
background-color: var(--accent-color);
|
background-color: var(--accent-color);
|
||||||
border-radius: 3rem;
|
border-radius: 3rem;
|
||||||
@ -960,6 +1020,15 @@ form select option {
|
|||||||
filter: saturate(0.8);
|
filter: saturate(0.8);
|
||||||
align-self: flex-start;
|
align-self: flex-start;
|
||||||
}
|
}
|
||||||
|
.fund-investor .tag {
|
||||||
|
display: inline-flex;
|
||||||
|
padding: 0.4rem 0.8rem;
|
||||||
|
border-radius: 0.5rem;
|
||||||
|
font-size: 0.8rem;
|
||||||
|
font-weight: 500;
|
||||||
|
color: var(--danger-color);
|
||||||
|
border: solid 0.1rem var(--danger-color);
|
||||||
|
}
|
||||||
|
|
||||||
.transaction-column {
|
.transaction-column {
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -982,7 +1051,7 @@ form select option {
|
|||||||
.start-date {
|
.start-date {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
margin-bottom: 3rem;
|
margin-bottom: 2rem;
|
||||||
background-color: rgba(var(--text-color), 0.06);
|
background-color: rgba(var(--text-color), 0.06);
|
||||||
padding: 0.8rem 1rem;
|
padding: 0.8rem 1rem;
|
||||||
border-radius: 0.5rem;
|
border-radius: 0.5rem;
|
||||||
@ -1001,10 +1070,9 @@ form select option {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.tapout-list {
|
.tapout-list {
|
||||||
display: grid;
|
display: flex;
|
||||||
gap: 1.5rem;
|
flex-wrap: wrap;
|
||||||
overflow-x: auto;
|
gap: 1rem 1.5rem;
|
||||||
grid-auto-flow: column;
|
|
||||||
justify-content: flex-start;
|
justify-content: flex-start;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1016,6 +1084,64 @@ form select option {
|
|||||||
justify-self: flex-end;
|
justify-self: flex-end;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.user-action-result__icon {
|
||||||
|
justify-self: center;
|
||||||
|
height: 4rem;
|
||||||
|
width: 4rem;
|
||||||
|
border-radius: 5rem;
|
||||||
|
margin-bottom: 2rem;
|
||||||
|
-webkit-animation: popup 1s;
|
||||||
|
animation: popup 1s;
|
||||||
|
}
|
||||||
|
.user-action-result__icon.success {
|
||||||
|
fill: rgba(var(--background-color), 1);
|
||||||
|
padding: 1rem;
|
||||||
|
background-color: #0bbe56;
|
||||||
|
}
|
||||||
|
.user-action-result__icon.failed {
|
||||||
|
background-color: rgba(var(--text-color), 0.03);
|
||||||
|
fill: var(--danger-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
@-webkit-keyframes popup {
|
||||||
|
0% {
|
||||||
|
opacity: 0;
|
||||||
|
transform: scale(0.2) translateY(600%);
|
||||||
|
}
|
||||||
|
10% {
|
||||||
|
transform: scale(0.2) translateY(5rem);
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
40% {
|
||||||
|
transform: scale(0.2) translateY(0);
|
||||||
|
}
|
||||||
|
80% {
|
||||||
|
transform: scale(1.1) translateY(0);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: scale(1) translateY(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes popup {
|
||||||
|
0% {
|
||||||
|
opacity: 0;
|
||||||
|
transform: scale(0.2) translateY(600%);
|
||||||
|
}
|
||||||
|
10% {
|
||||||
|
transform: scale(0.2) translateY(5rem);
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
40% {
|
||||||
|
transform: scale(0.2) translateY(0);
|
||||||
|
}
|
||||||
|
80% {
|
||||||
|
transform: scale(1.1) translateY(0);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: scale(1) translateY(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
@media only screen and (max-width: 640px) {
|
@media only screen and (max-width: 640px) {
|
||||||
#main_header {
|
#main_header {
|
||||||
grid-template-areas: ". profile-button";
|
grid-template-areas: ". profile-button";
|
||||||
@ -1023,19 +1149,27 @@ form select option {
|
|||||||
#main_header .dropdown {
|
#main_header .dropdown {
|
||||||
grid-area: profile-button;
|
grid-area: profile-button;
|
||||||
}
|
}
|
||||||
#homepage__hero-section {
|
|
||||||
padding: 2rem 0 20rem 0;
|
|
||||||
margin-bottom: -16rem;
|
|
||||||
}
|
|
||||||
.investor-input {
|
.investor-input {
|
||||||
grid-template-columns: 1fr auto;
|
grid-template-columns: 1fr auto;
|
||||||
grid-template-areas: ". close" ". close";
|
grid-template-areas: ". close" ". close";
|
||||||
}
|
}
|
||||||
|
.fund-block {
|
||||||
|
margin: 0 -1rem;
|
||||||
|
}
|
||||||
.fund-link {
|
.fund-link {
|
||||||
grid-column: 2/3;
|
grid-column: 2/3;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@media only screen and (min-width: 640px) {
|
@media only screen and (min-width: 640px) {
|
||||||
|
sm-popup {
|
||||||
|
--width: 26rem;
|
||||||
|
}
|
||||||
|
.popup__header {
|
||||||
|
padding: 1.5rem 1.5rem 0 0.75rem;
|
||||||
|
}
|
||||||
|
#home_page {
|
||||||
|
--side-padding: 8vw;
|
||||||
|
}
|
||||||
#main_header {
|
#main_header {
|
||||||
padding: 2rem calc(5vw - 0.4rem);
|
padding: 2rem calc(5vw - 0.4rem);
|
||||||
grid-template-columns: auto 1fr auto;
|
grid-template-columns: auto 1fr auto;
|
||||||
|
|||||||
2
css/main.min.css
vendored
2
css/main.min.css
vendored
File diff suppressed because one or more lines are too long
182
css/main.scss
182
css/main.scss
@ -15,30 +15,34 @@ body {
|
|||||||
body {
|
body {
|
||||||
--accent-color: #2353ff;
|
--accent-color: #2353ff;
|
||||||
--light-shade: rgba(var(--text-color), 0.06);
|
--light-shade: rgba(var(--text-color), 0.06);
|
||||||
--text-color: 17, 17, 17;
|
--text-color: 20, 20, 20;
|
||||||
--text-color-light: 100, 100, 100;
|
--foreground-color: 252, 253, 255;
|
||||||
--foreground-color: 255, 255, 255;
|
--background-color: 241, 243, 248;
|
||||||
--background-color: #f6f6f6;
|
--danger-color: rgb(255, 75, 75);
|
||||||
--error-color: red;
|
--green: #1cad59;
|
||||||
--green: #00843b;
|
--yellow: rgb(220, 165, 0);
|
||||||
color: rgba(var(--text-color), 1);
|
color: rgba(var(--text-color), 1);
|
||||||
background: var(--background-color);
|
background: rgba(var(--background-color), 1);
|
||||||
}
|
}
|
||||||
body[data-theme="dark"] {
|
body[data-theme="dark"] {
|
||||||
--accent-color: #2353ff;
|
--accent-color: #2353ff;
|
||||||
--green: #13ff5a;
|
--text-color: 200, 200, 200;
|
||||||
--text-color: 240, 240, 240;
|
--foreground-color: 27, 28, 29;
|
||||||
--text-color-light: 170, 170, 170;
|
--background-color: 21, 22, 22;
|
||||||
--foreground-color: 20, 20, 20;
|
--danger-color: rgb(255, 106, 106);
|
||||||
--background-color: #0a0a0a;
|
--green: #00e676;
|
||||||
--error-color: rgb(255, 106, 106);
|
--yellow: rgb(255, 213, 5);
|
||||||
::-webkit-calendar-picker-indicator {
|
::-webkit-calendar-picker-indicator {
|
||||||
filter: invert(1);
|
filter: invert(1);
|
||||||
}
|
}
|
||||||
sm-input.outlined {
|
a:any-link {
|
||||||
--active-placeholder-color: rgba(var(--text-color), 1);
|
filter: saturate(0.5) brightness(2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.overpass {
|
||||||
|
font-family: "Overpass", sans-serif;
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
.h1 {
|
.h1 {
|
||||||
font-size: 6rem;
|
font-size: 6rem;
|
||||||
}
|
}
|
||||||
@ -47,6 +51,8 @@ body[data-theme="dark"] {
|
|||||||
}
|
}
|
||||||
.h3 {
|
.h3 {
|
||||||
font-size: 3rem;
|
font-size: 3rem;
|
||||||
|
line-height: 1.1;
|
||||||
|
letter-spacing: -0.02em;
|
||||||
}
|
}
|
||||||
.h4 {
|
.h4 {
|
||||||
font-size: 2rem;
|
font-size: 2rem;
|
||||||
@ -163,6 +169,12 @@ button,
|
|||||||
button:disabled {
|
button:disabled {
|
||||||
opacity: 0.5;
|
opacity: 0.5;
|
||||||
}
|
}
|
||||||
|
.cta {
|
||||||
|
text-transform: uppercase;
|
||||||
|
font-weight: 700;
|
||||||
|
letter-spacing: 0.05em;
|
||||||
|
padding: 0.8rem 1rem;
|
||||||
|
}
|
||||||
a:any-link {
|
a:any-link {
|
||||||
position: relative;
|
position: relative;
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
@ -188,6 +200,38 @@ a:any-link:focus-visible {
|
|||||||
width: 1.2rem;
|
width: 1.2rem;
|
||||||
fill: rgba(var(--text-color), 1);
|
fill: rgba(var(--text-color), 1);
|
||||||
}
|
}
|
||||||
|
.multi-state-button {
|
||||||
|
display: grid;
|
||||||
|
text-align: center;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
& > * {
|
||||||
|
grid-area: 1/1/2/2;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
sm-spinner {
|
||||||
|
justify-self: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sm-spinner {
|
||||||
|
--size: 1.5rem;
|
||||||
|
--stroke-width: 0.1rem;
|
||||||
|
}
|
||||||
|
.password-field {
|
||||||
|
label {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
input:checked ~ .visible {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
input:not(:checked) ~ .invisible {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
sm-input,
|
sm-input,
|
||||||
sm-textarea {
|
sm-textarea {
|
||||||
@ -337,12 +381,9 @@ ul {
|
|||||||
opacity: 0;
|
opacity: 0;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
.hide-completely {
|
.hidden {
|
||||||
display: none !important;
|
display: none !important;
|
||||||
}
|
}
|
||||||
.no-transformations {
|
|
||||||
transform: none !important;
|
|
||||||
}
|
|
||||||
.overflow-ellipsis {
|
.overflow-ellipsis {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
@ -384,6 +425,14 @@ ul {
|
|||||||
.observe-empty-state:not(:empty) ~ .empty-state {
|
.observe-empty-state:not(:empty) ~ .empty-state {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
.popup__header {
|
||||||
|
display: grid;
|
||||||
|
gap: 0.5rem;
|
||||||
|
width: 100%;
|
||||||
|
padding: 0 1.5rem 0 0.5rem;
|
||||||
|
align-items: center;
|
||||||
|
grid-template-columns: auto 1fr auto;
|
||||||
|
}
|
||||||
|
|
||||||
#loading_page,
|
#loading_page,
|
||||||
#error_page {
|
#error_page {
|
||||||
@ -499,17 +548,13 @@ ul {
|
|||||||
}
|
}
|
||||||
#main_header__logo {
|
#main_header__logo {
|
||||||
fill: white;
|
fill: white;
|
||||||
height: 2.4rem;
|
height: 1.5rem;
|
||||||
width: 2.4rem;
|
width: 1.5rem;
|
||||||
margin-left: -0.3rem;
|
|
||||||
}
|
}
|
||||||
.header__company-name {
|
.header__company-name {
|
||||||
|
font-size: 1em;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
}
|
}
|
||||||
.header__app-name {
|
|
||||||
font-weight: 700;
|
|
||||||
font-size: 1.2rem;
|
|
||||||
}
|
|
||||||
#current_price {
|
#current_price {
|
||||||
justify-self: flex-start;
|
justify-self: flex-start;
|
||||||
}
|
}
|
||||||
@ -577,7 +622,7 @@ ul {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#home_page {
|
#home_page {
|
||||||
--side-padding: 5vw;
|
--side-padding: 1rem;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
padding: 0 max(1rem, var(--side-padding));
|
padding: 0 max(1rem, var(--side-padding));
|
||||||
@ -585,7 +630,7 @@ ul {
|
|||||||
}
|
}
|
||||||
#homepage__hero-section {
|
#homepage__hero-section {
|
||||||
color: white;
|
color: white;
|
||||||
padding: 2rem 0 12rem 0;
|
padding: 2rem var(--side-padding) 9rem var(--side-padding);
|
||||||
margin: 0 calc(-1 * max(1rem, var(--side-padding))) -5.5rem calc(-1 * max(1rem, var(--side-padding)));
|
margin: 0 calc(-1 * max(1rem, var(--side-padding))) -5.5rem calc(-1 * max(1rem, var(--side-padding)));
|
||||||
background-image: url(../assets/bg-1.svg);
|
background-image: url(../assets/bg-1.svg);
|
||||||
background-color: var(--accent-color);
|
background-color: var(--accent-color);
|
||||||
@ -594,6 +639,11 @@ ul {
|
|||||||
color: rgba($color: #fff, $alpha: 0.8);
|
color: rgba($color: #fff, $alpha: 0.8);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#refresh_button {
|
||||||
|
color: var(--accent-color);
|
||||||
|
background-color: white;
|
||||||
|
border: solid thin rgba(0, 0, 0, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
.fund-list__header {
|
.fund-list__header {
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -650,7 +700,7 @@ ul {
|
|||||||
#fund_list {
|
#fund_list {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 1.5rem;
|
gap: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
#fund_list__empty-state {
|
#fund_list__empty-state {
|
||||||
@ -749,6 +799,9 @@ form {
|
|||||||
padding: 1rem;
|
padding: 1rem;
|
||||||
border-radius: 0.5rem;
|
border-radius: 0.5rem;
|
||||||
border: solid thin rgba(var(--text-color), 0.2);
|
border: solid thin rgba(var(--text-color), 0.2);
|
||||||
|
& > .grid:first-of-type {
|
||||||
|
width: min(40ch, 100%);
|
||||||
|
}
|
||||||
&__redeem {
|
&__redeem {
|
||||||
background-color: var(--accent-color);
|
background-color: var(--accent-color);
|
||||||
border-radius: 3rem;
|
border-radius: 3rem;
|
||||||
@ -757,6 +810,15 @@ form {
|
|||||||
filter: saturate(0.8);
|
filter: saturate(0.8);
|
||||||
align-self: flex-start;
|
align-self: flex-start;
|
||||||
}
|
}
|
||||||
|
.tag {
|
||||||
|
display: inline-flex;
|
||||||
|
padding: 0.4rem 0.8rem;
|
||||||
|
border-radius: 0.5rem;
|
||||||
|
font-size: 0.8rem;
|
||||||
|
font-weight: 500;
|
||||||
|
color: var(--danger-color);
|
||||||
|
border: solid 0.1rem var(--danger-color);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.transaction-column {
|
.transaction-column {
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -777,7 +839,7 @@ form {
|
|||||||
.start-date {
|
.start-date {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
margin-bottom: 3rem;
|
margin-bottom: 2rem;
|
||||||
background-color: rgba(var(--text-color), 0.06);
|
background-color: rgba(var(--text-color), 0.06);
|
||||||
padding: 0.8rem 1rem;
|
padding: 0.8rem 1rem;
|
||||||
border-radius: 0.5rem;
|
border-radius: 0.5rem;
|
||||||
@ -793,10 +855,9 @@ form {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
.tapout-list {
|
.tapout-list {
|
||||||
display: grid;
|
display: flex;
|
||||||
gap: 1.5rem;
|
flex-wrap: wrap;
|
||||||
overflow-x: auto;
|
gap: 1rem 1.5rem;
|
||||||
grid-auto-flow: column;
|
|
||||||
justify-content: flex-start;
|
justify-content: flex-start;
|
||||||
}
|
}
|
||||||
.tapout-list li {
|
.tapout-list li {
|
||||||
@ -805,6 +866,42 @@ form {
|
|||||||
.fund-link {
|
.fund-link {
|
||||||
justify-self: flex-end;
|
justify-self: flex-end;
|
||||||
}
|
}
|
||||||
|
.user-action-result__icon {
|
||||||
|
justify-self: center;
|
||||||
|
height: 4rem;
|
||||||
|
width: 4rem;
|
||||||
|
border-radius: 5rem;
|
||||||
|
margin-bottom: 2rem;
|
||||||
|
animation: popup 1s;
|
||||||
|
&.success {
|
||||||
|
fill: rgba(var(--background-color), 1);
|
||||||
|
padding: 1rem;
|
||||||
|
background-color: #0bbe56;
|
||||||
|
}
|
||||||
|
&.failed {
|
||||||
|
background-color: rgba(var(--text-color), 0.03);
|
||||||
|
fill: var(--danger-color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@keyframes popup {
|
||||||
|
0% {
|
||||||
|
opacity: 0;
|
||||||
|
transform: scale(0.2) translateY(600%);
|
||||||
|
}
|
||||||
|
10% {
|
||||||
|
transform: scale(0.2) translateY(5rem);
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
40% {
|
||||||
|
transform: scale(0.2) translateY(0);
|
||||||
|
}
|
||||||
|
80% {
|
||||||
|
transform: scale(1.1) translateY(0);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: scale(1) translateY(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@media only screen and (max-width: 640px) {
|
@media only screen and (max-width: 640px) {
|
||||||
#main_header {
|
#main_header {
|
||||||
@ -813,19 +910,28 @@ form {
|
|||||||
grid-area: profile-button;
|
grid-area: profile-button;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#homepage__hero-section {
|
|
||||||
padding: 2rem 0 20rem 0;
|
|
||||||
margin-bottom: -16rem;
|
|
||||||
}
|
|
||||||
.investor-input {
|
.investor-input {
|
||||||
grid-template-columns: 1fr auto;
|
grid-template-columns: 1fr auto;
|
||||||
grid-template-areas: ". close" ". close";
|
grid-template-areas: ". close" ". close";
|
||||||
}
|
}
|
||||||
|
.fund-block {
|
||||||
|
margin: 0 -1rem;
|
||||||
|
}
|
||||||
.fund-link {
|
.fund-link {
|
||||||
grid-column: 2/3;
|
grid-column: 2/3;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@media only screen and (min-width: 640px) {
|
@media only screen and (min-width: 640px) {
|
||||||
|
sm-popup {
|
||||||
|
--width: 26rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.popup__header {
|
||||||
|
padding: 1.5rem 1.5rem 0 0.75rem;
|
||||||
|
}
|
||||||
|
#home_page {
|
||||||
|
--side-padding: 8vw;
|
||||||
|
}
|
||||||
#main_header {
|
#main_header {
|
||||||
padding: 2rem calc((10vw / 2) - 0.4rem);
|
padding: 2rem calc((10vw / 2) - 0.4rem);
|
||||||
grid-template-columns: auto 1fr auto;
|
grid-template-columns: auto 1fr auto;
|
||||||
|
|||||||
755
index.html
755
index.html
@ -10,13 +10,13 @@
|
|||||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||||
<link
|
<link
|
||||||
href="https://fonts.googleapis.com/css2?family=Roboto:ital,wght@0,400;0,500;0,700;1,400;1,500;1,700&display=swap"
|
href="https://fonts.googleapis.com/css2?family=Overpass:wght@700&family=Roboto:ital,wght@0,400;0,500;0,700;1,400;1,500;1,700&display=swap"
|
||||||
rel="stylesheet">
|
rel="stylesheet">
|
||||||
<script id="floGlobals">
|
<script id="floGlobals">
|
||||||
/* Constants for FLO blockchain operations !!Make sure to add this at begining!! */
|
/* Constants for FLO blockchain operations !!Make sure to add this at begining!! */
|
||||||
const floGlobals = {
|
const floGlobals = {
|
||||||
blockchain: "FLO",
|
blockchain: "FLO",
|
||||||
adminID: "FFXy5pJnfzu2fCDLhpUremyXQjGtFpgCDN",
|
adminID: "FT9qkvuWXWBDRhHd42tDr5nMYFSx7bEhV7",
|
||||||
application: "BobsFund"
|
application: "BobsFund"
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
@ -44,7 +44,7 @@
|
|||||||
<body onload="onLoadStartUp()" data-theme="light">
|
<body onload="onLoadStartUp()" data-theme="light">
|
||||||
<sm-notifications id="notification_drawer"></sm-notifications>
|
<sm-notifications id="notification_drawer"></sm-notifications>
|
||||||
<article id="loading_page" class="page">
|
<article id="loading_page" class="page">
|
||||||
<h2 class="h2">Bob's Fund</h2>
|
<h3 class="h3 overpass">Bob's Fund</h3>
|
||||||
<svg id="loader" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64">
|
<svg id="loader" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64">
|
||||||
<polygon points="17.76 23.78 17.76 40.22 32 48.44 46.24 40.22 46.24 23.78 32 15.56 17.76 23.78" />
|
<polygon points="17.76 23.78 17.76 40.22 32 48.44 46.24 40.22 46.24 23.78 32 15.56 17.76 23.78" />
|
||||||
<polyline points="17.76 23.78 32 32 46.24 23.78" />
|
<polyline points="17.76 23.78 32 32 46.24 23.78" />
|
||||||
@ -62,8 +62,8 @@
|
|||||||
<h4 class="h4 color-0-8 weight-500">RanchiMall</h4>
|
<h4 class="h4 color-0-8 weight-500">RanchiMall</h4>
|
||||||
</footer>
|
</footer>
|
||||||
</article>
|
</article>
|
||||||
<article id="error_page" class="page hide-completely">
|
<article id="error_page" class="page hidden">
|
||||||
<h2 class="h2">Bob's Fund</h2>
|
<h3 class="h3 overpass">Bob's Fund</h3>
|
||||||
<svg class="sad-face" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 500 500">
|
<svg class="sad-face" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 500 500">
|
||||||
<g class="face">
|
<g class="face">
|
||||||
<g class="eyes">
|
<g class="eyes">
|
||||||
@ -89,7 +89,7 @@
|
|||||||
<h4 class="h4 color-0-8 weight-500">RanchiMall</h4>
|
<h4 class="h4 color-0-8 weight-500">RanchiMall</h4>
|
||||||
</footer>
|
</footer>
|
||||||
</article>
|
</article>
|
||||||
<header id="main_header" class="hide-completely">
|
<header id="main_header" class="hidden">
|
||||||
<div class="flex align-items-center">
|
<div class="flex align-items-center">
|
||||||
<svg id="main_header__logo" class="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
|
<svg id="main_header__logo" class="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
|
||||||
<path
|
<path
|
||||||
@ -97,7 +97,6 @@
|
|||||||
</svg>
|
</svg>
|
||||||
<div class="grid">
|
<div class="grid">
|
||||||
<h5 class="header__company-name">RanchiMall</h5>
|
<h5 class="header__company-name">RanchiMall</h5>
|
||||||
<h3 class="header__app-name">Bob's Fund</h3>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="current_price" class="grid gap-1 flow-column align-items-center">
|
<div id="current_price" class="grid gap-1 flow-column align-items-center">
|
||||||
@ -115,7 +114,7 @@
|
|||||||
</g>
|
</g>
|
||||||
</svg>
|
</svg>
|
||||||
</button>
|
</button>
|
||||||
<ul id="profile_dropdown" class="dropdown__panel hide-completely">
|
<ul id="profile_dropdown" class="dropdown__panel hidden">
|
||||||
<li class="grid gap-0-5">
|
<li class="grid gap-0-5">
|
||||||
<h4 class="weight-700 margin-bottom-0-5r">Preferred currency</h4>
|
<h4 class="weight-700 margin-bottom-0-5r">Preferred currency</h4>
|
||||||
<p>This will convert all amounts to preferred currency.</p>
|
<p>This will convert all amounts to preferred currency.</p>
|
||||||
@ -134,9 +133,9 @@
|
|||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
<main id="home_page" class="page hide-completely">
|
<main id="home_page" class="page hidden">
|
||||||
<section id="homepage__hero-section" class="full-bleed page-layout">
|
<section id="homepage__hero-section">
|
||||||
<h3 class="h3 margin-bottom-1r">Bob's Fund<br>on FLO Blockchain</h3>
|
<h3 class="h3 overpass margin-bottom-1r">Bob's Fund<br>on FLO Blockchain</h3>
|
||||||
<p>
|
<p>
|
||||||
Bob's Fund is a 20 year long term Bitcoin price linked product. Investors are entitled to 100%
|
Bob's Fund is a 20 year long term Bitcoin price linked product. Investors are entitled to 100%
|
||||||
of Bitcoin price gains, but they must hold for 20 years. Over a very long time period, investor returns
|
of Bitcoin price gains, but they must hold for 20 years. Over a very long time period, investor returns
|
||||||
@ -147,9 +146,9 @@
|
|||||||
</section>
|
</section>
|
||||||
<header class="fund-list__header">
|
<header class="fund-list__header">
|
||||||
<h4 class="h4">Funds</h4>
|
<h4 class="h4">Funds</h4>
|
||||||
<button id="refresh_button" class="justify-right button--primary">Refresh</button>
|
<button id="refresh_button" class="button justify-right">Refresh</button>
|
||||||
</header>
|
</header>
|
||||||
<sm-input id="search_investor" type="search" placeholder="Search investor with FLO ID">
|
<sm-input id="search_investor" type="search" placeholder="Search investor with FLO address">
|
||||||
<svg class="icon" slot="icon" xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24"
|
<svg class="icon" slot="icon" xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24"
|
||||||
width="24px" fill="#000000">
|
width="24px" fill="#000000">
|
||||||
<path d="M0 0h24v24H0V0z" fill="none" />
|
<path d="M0 0h24v24H0V0z" fill="none" />
|
||||||
@ -162,7 +161,7 @@
|
|||||||
</div> -->
|
</div> -->
|
||||||
<section>
|
<section>
|
||||||
<ul id="fund_list"></ul>
|
<ul id="fund_list"></ul>
|
||||||
<div id="fund_list__empty-state" class="grid hide-completely">
|
<div id="fund_list__empty-state" class="grid hidden">
|
||||||
<svg class="icon icon--big" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24"
|
<svg class="icon icon--big" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24"
|
||||||
height="24">
|
height="24">
|
||||||
<path fill="none" d="M0 0h24v24H0z" />
|
<path fill="none" d="M0 0h24v24H0z" />
|
||||||
@ -172,7 +171,7 @@
|
|||||||
<h4>No Funds found</h4>
|
<h4>No Funds found</h4>
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
<article id="admin_page" class="page page-layout hide-completely">
|
<article id="admin_page" class="page page-layout hidden">
|
||||||
<header class="flex margin-top-1-5 align-items-center margin-bottom-1-5r">
|
<header class="flex margin-top-1-5 align-items-center margin-bottom-1-5r">
|
||||||
<button onclick="showPage('home_page')">
|
<button onclick="showPage('home_page')">
|
||||||
<svg class="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24">
|
<svg class="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24">
|
||||||
@ -218,7 +217,7 @@
|
|||||||
Tapout
|
Tapout
|
||||||
</div>
|
</div>
|
||||||
</sm-switch>
|
</sm-switch>
|
||||||
<section id="tapout_container" class="grid gap-1-5 hide-completely">
|
<section id="tapout_container" class="grid gap-1-5 hidden">
|
||||||
<div class="grid gap-0-5">
|
<div class="grid gap-0-5">
|
||||||
Tapout window
|
Tapout window
|
||||||
<div class="flex">
|
<div class="flex">
|
||||||
@ -248,14 +247,14 @@
|
|||||||
</label>
|
</label>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<div id="fund_selector_container" class="grid margin-bottom-0-5r hide-completely">
|
<div id="fund_selector_container" class="grid margin-bottom-0-5r hidden">
|
||||||
<span class="margin-bottom-0-5r">Select Fund</span>
|
<span class="margin-bottom-0-5r">Select Fund</span>
|
||||||
<sm-select id="fund_selector"></sm-select>
|
<sm-select id="fund_selector"></sm-select>
|
||||||
</div>
|
</div>
|
||||||
<h4>Add Investors</h4>
|
<h4>Add Investors</h4>
|
||||||
<ul id="investors_input_list" class="grid gap-1">
|
<ul id="investors_input_list" class="grid gap-1">
|
||||||
<li class="investor-input grid">
|
<li class="investor-input grid">
|
||||||
<sm-input placeholder="FLO ID" class="outlined" animate></sm-input>
|
<sm-input placeholder="FLO address" class="outlined" animate></sm-input>
|
||||||
<sm-input placeholder="Amount(₹)" type="number" min=0 class="outlined" animate></sm-input>
|
<sm-input placeholder="Amount(₹)" type="number" min=0 class="outlined" animate></sm-input>
|
||||||
<button class="remove-investor" title="Remove this investor">
|
<button class="remove-investor" title="Remove this investor">
|
||||||
<svg class="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24">
|
<svg class="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24">
|
||||||
@ -274,13 +273,13 @@
|
|||||||
</svg>
|
</svg>
|
||||||
Add new
|
Add new
|
||||||
</button>
|
</button>
|
||||||
<button id="add_investors_button" type="submit"
|
<button id="add_investors_button" type="submit" class="button--primary justify-self-start hidden">Add
|
||||||
class="button--primary justify-self-start hide-completely">Add Investors</button>
|
Investors</button>
|
||||||
<button id="create_fund_button" type="submit" class="button--primary justify-self-start">Create
|
<button id="create_fund_button" type="submit" class="button--primary justify-self-start">Create
|
||||||
Fund</button>
|
Fund</button>
|
||||||
</form>
|
</form>
|
||||||
</article>
|
</article>
|
||||||
<article id="confirm_term_page" class="page page-layout hide-completely">
|
<article id="confirm_term_page" class="page page-layout hidden">
|
||||||
<header class="flex margin-top-1-5 align-items-center margin-bottom-1-5r">
|
<header class="flex margin-top-1-5 align-items-center margin-bottom-1-5r">
|
||||||
<button class="back-button" onclick="showPage('admin_page')">
|
<button class="back-button" onclick="showPage('admin_page')">
|
||||||
<svg class="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24">
|
<svg class="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24">
|
||||||
@ -300,7 +299,7 @@
|
|||||||
term</button>
|
term</button>
|
||||||
</form>
|
</form>
|
||||||
</article>
|
</article>
|
||||||
<article id="confirm_fund_page" class="page page-layout hide-completely">
|
<article id="confirm_fund_page" class="page page-layout hidden">
|
||||||
<header class="flex margin-top-1-5 align-items-center margin-bottom-1-5r">
|
<header class="flex margin-top-1-5 align-items-center margin-bottom-1-5r">
|
||||||
<button class="back-button" onclick="showPage('admin_page')">
|
<button class="back-button" onclick="showPage('admin_page')">
|
||||||
<svg class="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24">
|
<svg class="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24">
|
||||||
@ -320,147 +319,73 @@
|
|||||||
Fund</button>
|
Fund</button>
|
||||||
</form>
|
</form>
|
||||||
</article>
|
</article>
|
||||||
|
<sm-popup id="redeem_popup">
|
||||||
|
<header slot="header" class="popup__header">
|
||||||
|
<button class="popup__header__close" onclick="closePopup()">
|
||||||
|
<svg class="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24">
|
||||||
|
<path fill="none" d="M0 0h24v24H0z" />
|
||||||
|
<path
|
||||||
|
d="M12 10.586l4.95-4.95 1.414 1.414-4.95 4.95 4.95 4.95-1.414 1.414-4.95-4.95-4.95 4.95-1.414-1.414 4.95-4.95-4.95-4.95L7.05 5.636z" />
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
<h3>Redeem fund</h3>
|
||||||
|
</header>
|
||||||
|
<div id="redeem_process">
|
||||||
|
<div id="redeem_precess__get_priv_key">
|
||||||
|
<sm-form class="grid gap-1-5">
|
||||||
|
<div id="redeem__id"></div>
|
||||||
|
<sm-input id="redeem_private_key" class="password-field" type="password"
|
||||||
|
placeholder="FLO private key" error-text="Private key is invalid" autofocus data-private-key
|
||||||
|
required>
|
||||||
|
<label slot="right" class="interact">
|
||||||
|
<input type="checkbox" class="hidden" autocomplete="off" readonly
|
||||||
|
onchange="togglePrivateKeyVisibility(this)">
|
||||||
|
<svg class="icon invisible" xmlns="http://www.w3.org/2000/svg" height="24px"
|
||||||
|
viewBox="0 0 24 24" width="24px" fill="#000000">
|
||||||
|
<title>Hide password</title>
|
||||||
|
<path d="M0 0h24v24H0zm0 0h24v24H0zm0 0h24v24H0zm0 0h24v24H0z" fill="none" />
|
||||||
|
<path
|
||||||
|
d="M12 7c2.76 0 5 2.24 5 5 0 .65-.13 1.26-.36 1.83l2.92 2.92c1.51-1.26 2.7-2.89 3.43-4.75-1.73-4.39-6-7.5-11-7.5-1.4 0-2.74.25-3.98.7l2.16 2.16C10.74 7.13 11.35 7 12 7zM2 4.27l2.28 2.28.46.46C3.08 8.3 1.78 10.02 1 12c1.73 4.39 6 7.5 11 7.5 1.55 0 3.03-.3 4.38-.84l.42.42L19.73 22 21 20.73 3.27 3 2 4.27zM7.53 9.8l1.55 1.55c-.05.21-.08.43-.08.65 0 1.66 1.34 3 3 3 .22 0 .44-.03.65-.08l1.55 1.55c-.67.33-1.41.53-2.2.53-2.76 0-5-2.24-5-5 0-.79.2-1.53.53-2.2zm4.31-.78l3.15 3.15.02-.16c0-1.66-1.34-3-3-3l-.17.01z" />
|
||||||
|
</svg>
|
||||||
|
<svg class="icon visible" xmlns="http://www.w3.org/2000/svg" height="24px"
|
||||||
|
viewBox="0 0 24 24" width="24px" fill="#000000">
|
||||||
|
<title>Show password</title>
|
||||||
|
<path d="M0 0h24v24H0z" fill="none" />
|
||||||
|
<path
|
||||||
|
d="M12 4.5C7 4.5 2.73 7.61 1 12c1.73 4.39 6 7.5 11 7.5s9.27-3.11 11-7.5c-1.73-4.39-6-7.5-11-7.5zM12 17c-2.76 0-5-2.24-5-5s2.24-5 5-5 5 2.24 5 5-2.24 5-5 5zm0-8c-1.66 0-3 1.34-3 3s1.34 3 3 3 3-1.34 3-3-1.34-3-3-3z" />
|
||||||
|
</svg>
|
||||||
|
</label>
|
||||||
|
</sm-input>
|
||||||
|
<div class="multi-state-button">
|
||||||
|
<button id="redeem_private_key_button" type="submit"
|
||||||
|
class="button button--primary cta">Redeem</button>
|
||||||
|
</div>
|
||||||
|
</sm-form>
|
||||||
|
</div>
|
||||||
|
<div class="grid gap-0-5 hidden justify-center text-center">
|
||||||
|
<svg class="icon user-action-result__icon success" xmlns="http://www.w3.org/2000/svg" height="24px"
|
||||||
|
viewBox="0 0 24 24" width="24px" fill="#000000">
|
||||||
|
<path d="M0 0h24v24H0V0z" fill="none" />
|
||||||
|
<path d="M9 16.2L4.8 12l-1.4 1.4L9 19 21 7l-1.4-1.4L9 16.2z" />
|
||||||
|
</svg>
|
||||||
|
<h4>Redeem request sent</h4>
|
||||||
|
<p>Balance may take upto 30mins to reflect in your FLO address</p>
|
||||||
|
</div>
|
||||||
|
<div class="grid gap-0-5 hidden justify-center text-center">
|
||||||
|
<svg class="icon user-action-result__icon failed" xmlns="http://www.w3.org/2000/svg" height="24px"
|
||||||
|
viewBox="0 0 24 24" width="24px" fill="#000000">
|
||||||
|
<path d="M0 0h24v24H0z" fill="none" />
|
||||||
|
<path
|
||||||
|
d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-2h2v2zm0-4h-2V7h2v6z" />
|
||||||
|
</svg>
|
||||||
|
<h3>Failed</h3>
|
||||||
|
<p id="redeem_failed_message"></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</sm-popup>
|
||||||
|
|
||||||
|
|
||||||
<script id="ui">
|
<script id="ui">
|
||||||
function formatAmount(amount = 0, currency = 'inr') {
|
|
||||||
amount = parseFloat(amount);
|
|
||||||
if (!amount)
|
|
||||||
return '₹0';
|
|
||||||
return amount.toLocaleString(currency === 'inr' ? `en-IN` : 'en-US', { style: 'currency', currency })
|
|
||||||
}
|
|
||||||
const render = {
|
|
||||||
investorInput() {
|
|
||||||
const investorInput = document.createElement('li')
|
|
||||||
investorInput.classList.add('investor-input', 'grid')
|
|
||||||
investorInput.innerHTML = `
|
|
||||||
<sm-input placeholder="FLO ID" class="outlined" animate></sm-input>
|
|
||||||
<sm-input placeholder="Amount(₹)" type="number" min=0 class="outlined" animate></sm-input>
|
|
||||||
<button class="remove-investor" title="Remove this investor">
|
|
||||||
<svg class="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path fill="none" d="M0 0h24v24H0z"/><path d="M12 10.586l4.95-4.95 1.414 1.414-4.95 4.95 4.95 4.95-1.414 1.414-4.95-4.95-4.95 4.95-1.414-1.414 4.95-4.95-4.95-4.95L7.05 5.636z"/></svg>
|
|
||||||
</button>
|
|
||||||
`
|
|
||||||
return investorInput
|
|
||||||
},
|
|
||||||
fundPlaceholder() {
|
|
||||||
const fund_ph = document.createElement('li')
|
|
||||||
fund_ph.classList.add('fund-placeholder', 'grid')
|
|
||||||
fund_ph.innerHTML = `
|
|
||||||
<div class="flex-grid justify-start">
|
|
||||||
<div class="placeholder__block"></div>
|
|
||||||
<div class="placeholder__block"></div>
|
|
||||||
<div class="placeholder__block"></div>
|
|
||||||
<div class="placeholder__block"></div>
|
|
||||||
</div>
|
|
||||||
<div class="grid flow-column gap-1">
|
|
||||||
<div class="placeholder__block"></div>
|
|
||||||
<div class="placeholder__block"></div>
|
|
||||||
</div>
|
|
||||||
<div class="placeholder__block justify-self-end"></div>
|
|
||||||
`
|
|
||||||
return fund_ph
|
|
||||||
},
|
|
||||||
investorCard(details) {
|
|
||||||
const {
|
|
||||||
floId,
|
|
||||||
amountInvested,
|
|
||||||
netValue,
|
|
||||||
fundId,
|
|
||||||
isRedeemable = false,
|
|
||||||
} = details
|
|
||||||
return html`
|
|
||||||
<li class="fund-investor" id=${`${fundId}_${floId}`} data-flo-id=${floId}>
|
|
||||||
<div class="grid">
|
|
||||||
<span class="label">FLO ID</span>
|
|
||||||
<span class="value flo-id">${floId}</span>
|
|
||||||
</div>
|
|
||||||
<div class="flex gap-1-5">
|
|
||||||
<div class="transaction-column">
|
|
||||||
<span class="label">Invested</span>
|
|
||||||
<span class="value amount-invested">${formatAmount(amountInvested[preferredCurrency], preferredCurrency)}</span>
|
|
||||||
</div>
|
|
||||||
<div class="transaction-column">
|
|
||||||
<span class="label">Present value</span>
|
|
||||||
<span class="value net-value" style="color: var(--green)">${formatAmount(netValue[preferredCurrency], preferredCurrency)}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<button class="button fund-investor__redeem" ?disabled=${!isRedeemable}>Redeem</button>
|
|
||||||
</li>
|
|
||||||
`
|
|
||||||
},
|
|
||||||
fundBlock(details) {
|
|
||||||
let {
|
|
||||||
fundTxs,
|
|
||||||
startDate,
|
|
||||||
endDate,
|
|
||||||
baseUsd,
|
|
||||||
baseBtc,
|
|
||||||
tapouts,
|
|
||||||
totalInvestment,
|
|
||||||
totalNet,
|
|
||||||
investorsFrag
|
|
||||||
} = details
|
|
||||||
const tapoutsFrag = []
|
|
||||||
for (let tapout in tapouts) {
|
|
||||||
const tapoutPoint = html`
|
|
||||||
<li class="tapout-point grid">
|
|
||||||
<span class="label">${tapout}</span>
|
|
||||||
<span class="value">${tapouts[tapout]}</span>
|
|
||||||
</li>`;
|
|
||||||
tapoutsFrag.push(tapoutPoint)
|
|
||||||
}
|
|
||||||
const renderedFundTxs = fundTxs.map((tx, index) => {
|
|
||||||
return html`<a href=${`${floBlockchainAPI.current_server}tx/${tx.txid}`}>Transaction ${index + 1}</a>`
|
|
||||||
})
|
|
||||||
|
|
||||||
return html.node`
|
|
||||||
<li class="fund-block">
|
|
||||||
<h3 class="start-date">${startDate} Fund</h3>
|
|
||||||
<div class="fund-block__details margin-bottom-3r">
|
|
||||||
<div class="grid">
|
|
||||||
<span class="label">End date</span>
|
|
||||||
<span class="value end-date">${bobsFund.dateFormat(endDate)}</span>
|
|
||||||
</div>
|
|
||||||
<div class="flex flex-wrap gap-1">
|
|
||||||
<div class="grid">
|
|
||||||
<span class="label">Initial BTC value</span>
|
|
||||||
<span class="value base-btc">${formatAmount(baseBtc[preferredCurrency], preferredCurrency)}</span>
|
|
||||||
</div>
|
|
||||||
<div class="grid">
|
|
||||||
<span class="label">Base USD rate</span>
|
|
||||||
<span class="value base-usd">${baseUsd.toLocaleString(`en-US`, { style: 'currency', currency: 'INR' })}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
${tapoutsFrag.length ? html`
|
|
||||||
<div class="tapout-container grid">
|
|
||||||
<span class="value margin-bottom-0-5r">Tapouts</span>
|
|
||||||
<ul class="tapout-list">${tapoutsFrag}</ul>
|
|
||||||
</div>` : ''}
|
|
||||||
<div class="flex flex-wrap gap-1">
|
|
||||||
<div class="grid">
|
|
||||||
<span class="label">Total investment</span>
|
|
||||||
<span class="value total-investment">${formatAmount(totalInvestment[preferredCurrency], preferredCurrency)}</span>
|
|
||||||
</div>
|
|
||||||
<div class="grid">
|
|
||||||
<span class="label">Total present value</span>
|
|
||||||
<span class="value net-value" style="color: var(--green)">${formatAmount(totalNet[preferredCurrency], preferredCurrency)}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="grid">
|
|
||||||
<span class="label">Fund transactions</span>
|
|
||||||
<div class="flex gap-0-5">${renderedFundTxs}</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="grid">
|
|
||||||
<h4 class="margin-bottom-0-5r">Investors</h4>
|
|
||||||
<ul class="investors-list grid">${investorsFrag}</ul>
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const { html, render: renderElem } = uhtml;
|
const { html, render: renderElem } = uhtml;
|
||||||
const domRefs = {}
|
const domRefs = {}
|
||||||
//Checks for internet connection status
|
//Checks for internet connection status
|
||||||
@ -512,6 +437,22 @@
|
|||||||
|
|
||||||
|
|
||||||
window.addEventListener("load", () => {
|
window.addEventListener("load", () => {
|
||||||
|
document.querySelectorAll('sm-input[data-flo-id]').forEach(input => input.customValidation = floCrypto.validateAddr)
|
||||||
|
document.querySelectorAll('sm-input[data-private-key]').forEach(input => input.customValidation = floCrypto.getPubKeyHex)
|
||||||
|
document.addEventListener('keyup', (e) => {
|
||||||
|
if (e.code === 'Escape') {
|
||||||
|
closePopup()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
document.addEventListener('keydown', e => {
|
||||||
|
if (e.key === '/') {
|
||||||
|
e.preventDefault();
|
||||||
|
getRef('search_investor').focusIn()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
document.addEventListener('copy', () => {
|
||||||
|
notify('copied', 'success')
|
||||||
|
})
|
||||||
document.addEventListener("pointerdown", (e) => {
|
document.addEventListener("pointerdown", (e) => {
|
||||||
if (e.target.closest("button:not([disabled]), .interact")) {
|
if (e.target.closest("button:not([disabled]), .interact")) {
|
||||||
createRipple(e, e.target.closest("button, .interact"));
|
createRipple(e, e.target.closest("button, .interact"));
|
||||||
@ -569,6 +510,387 @@
|
|||||||
}, wait);
|
}, wait);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
let zIndex = 50
|
||||||
|
// function required for popups or modals to appear
|
||||||
|
function openPopup(popupId, pinned) {
|
||||||
|
zIndex++
|
||||||
|
getRef(popupId).setAttribute('style', `z-index: ${zIndex}`)
|
||||||
|
getRef(popupId).show({ pinned })
|
||||||
|
return getRef(popupId);
|
||||||
|
}
|
||||||
|
|
||||||
|
// hides the popup or modal
|
||||||
|
function closePopup() {
|
||||||
|
if (popupStack.peek() === undefined)
|
||||||
|
return;
|
||||||
|
popupStack.peek().popup.hide()
|
||||||
|
}
|
||||||
|
function buttonLoader(id, show) {
|
||||||
|
const button = typeof id === 'string' ? getRef(id) : id;
|
||||||
|
button.disabled = show;
|
||||||
|
const animOptions = {
|
||||||
|
duration: floGlobals.prefersReducedMotion ? 0 : 200,
|
||||||
|
fill: 'forwards',
|
||||||
|
easing: 'ease'
|
||||||
|
}
|
||||||
|
if (show) {
|
||||||
|
button.animate([
|
||||||
|
{
|
||||||
|
clipPath: 'circle(100%)',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
clipPath: 'circle(0)',
|
||||||
|
},
|
||||||
|
], animOptions)
|
||||||
|
button.parentNode.append(document.createElement('sm-spinner'))
|
||||||
|
} else {
|
||||||
|
button.getAnimations().forEach(anim => anim.cancel())
|
||||||
|
const potentialTarget = button.parentNode.querySelector('sm-spinner')
|
||||||
|
if (potentialTarget) potentialTarget.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
document.addEventListener('popupopened', e => {
|
||||||
|
getRef('home_page').setAttribute('inert', '')
|
||||||
|
})
|
||||||
|
document.addEventListener('popupclosed', e => {
|
||||||
|
switch (e.detail.popup.id) {
|
||||||
|
case 'redeem_popup':
|
||||||
|
showChildElement(getRef('redeem_process'), 0);
|
||||||
|
buttonLoader('redeem_private_key_button', false)
|
||||||
|
getRef('redeem_private_key_button').disabled = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (popupStack.items.length === 0) {
|
||||||
|
getRef('home_page').removeAttribute('inert')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
const slideInLeft = [
|
||||||
|
{
|
||||||
|
opacity: 0,
|
||||||
|
transform: 'translateX(1rem)'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
opacity: 1,
|
||||||
|
transform: 'translateX(0)'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
const slideOutLeft = [
|
||||||
|
{
|
||||||
|
opacity: 1,
|
||||||
|
transform: 'translateX(0)'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
opacity: 0,
|
||||||
|
transform: 'translateX(-1rem)'
|
||||||
|
},
|
||||||
|
]
|
||||||
|
const slideInRight = [
|
||||||
|
{
|
||||||
|
opacity: 0,
|
||||||
|
transform: 'translateX(-1rem)'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
opacity: 1,
|
||||||
|
transform: 'translateX(0)'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
const slideOutRight = [
|
||||||
|
{
|
||||||
|
opacity: 1,
|
||||||
|
transform: 'translateX(0)'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
opacity: 0,
|
||||||
|
transform: 'translateX(1rem)'
|
||||||
|
},
|
||||||
|
]
|
||||||
|
const slideInDown = [
|
||||||
|
{
|
||||||
|
opacity: 0,
|
||||||
|
transform: 'translateY(-1rem)'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
opacity: 1,
|
||||||
|
transform: 'translateY(0)'
|
||||||
|
},
|
||||||
|
]
|
||||||
|
const slideOutDown = [
|
||||||
|
{
|
||||||
|
opacity: 1,
|
||||||
|
transform: 'translateY(0)'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
opacity: 0,
|
||||||
|
transform: 'translateY(1rem)'
|
||||||
|
},
|
||||||
|
]
|
||||||
|
const slideInUp = [
|
||||||
|
{
|
||||||
|
opacity: 0,
|
||||||
|
transform: 'translateY(1rem)'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
opacity: 1,
|
||||||
|
transform: 'translateY(0)'
|
||||||
|
},
|
||||||
|
]
|
||||||
|
const slideOutUp = [
|
||||||
|
{
|
||||||
|
opacity: 1,
|
||||||
|
transform: 'translateY(0)'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
opacity: 0,
|
||||||
|
transform: 'translateY(-1rem)'
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
function showChildElement(id, index, options = {}) {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
const { mobileView = false, entry, exit } = options
|
||||||
|
const animOptions = {
|
||||||
|
duration: floGlobals.prefersReducedMotion ? 0 : 150,
|
||||||
|
easing: 'ease',
|
||||||
|
fill: 'forwards'
|
||||||
|
}
|
||||||
|
const parent = typeof id === 'string' ? document.getElementById(id) : id;
|
||||||
|
const visibleElement = [...parent.children].find(elem => !elem.classList.contains(mobileView ? 'hide-on-mobile' : 'hidden'));
|
||||||
|
if (visibleElement === parent.children[index]) return;
|
||||||
|
visibleElement.getAnimations().forEach(anim => anim.cancel())
|
||||||
|
parent.children[index].getAnimations().forEach(anim => anim.cancel())
|
||||||
|
if (visibleElement) {
|
||||||
|
if (exit) {
|
||||||
|
parent.style.overflow = 'hidden'
|
||||||
|
visibleElement.animate(exit, animOptions).onfinish = () => {
|
||||||
|
visibleElement.classList.add(mobileView ? 'hide-on-mobile' : 'hidden')
|
||||||
|
parent.style.overflow = ''
|
||||||
|
}
|
||||||
|
parent.children[index].classList.remove(mobileView ? 'hide-on-mobile' : 'hidden')
|
||||||
|
if (entry)
|
||||||
|
parent.children[index].animate(entry, animOptions).onfinish = () => resolve()
|
||||||
|
} else {
|
||||||
|
visibleElement.classList.add(mobileView ? 'hide-on-mobile' : 'hidden')
|
||||||
|
parent.children[index].classList.remove(mobileView ? 'hide-on-mobile' : 'hidden')
|
||||||
|
resolve()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
parent.children[index].classList.remove(mobileView ? 'hide-on-mobile' : 'hidden')
|
||||||
|
parent.children[index].animate(entry, animOptions).onfinish = () => resolve()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
function togglePrivateKeyVisibility(input) {
|
||||||
|
const target = input.closest('sm-input')
|
||||||
|
target.type = target.type === 'password' ? 'text' : 'password';
|
||||||
|
target.focusIn()
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatAmount(amount = 0, currency = 'inr') {
|
||||||
|
amount = parseFloat(amount);
|
||||||
|
if (!amount)
|
||||||
|
return '₹0';
|
||||||
|
return amount.toLocaleString(currency === 'inr' ? `en-IN` : 'en-US', { style: 'currency', currency })
|
||||||
|
}
|
||||||
|
const render = {
|
||||||
|
investorInput() {
|
||||||
|
const investorInput = document.createElement('li')
|
||||||
|
investorInput.classList.add('investor-input', 'grid')
|
||||||
|
investorInput.innerHTML = `
|
||||||
|
<sm-input placeholder="FLO address" class="outlined" animate></sm-input>
|
||||||
|
<sm-input placeholder="Amount(₹)" type="number" min=0 class="outlined" animate></sm-input>
|
||||||
|
<button class="remove-investor" title="Remove this investor">
|
||||||
|
<svg class="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path fill="none" d="M0 0h24v24H0z"/><path d="M12 10.586l4.95-4.95 1.414 1.414-4.95 4.95 4.95 4.95-1.414 1.414-4.95-4.95-4.95 4.95-1.414-1.414 4.95-4.95-4.95-4.95L7.05 5.636z"/></svg>
|
||||||
|
</button>
|
||||||
|
`
|
||||||
|
return investorInput
|
||||||
|
},
|
||||||
|
fundPlaceholder() {
|
||||||
|
const fund_ph = document.createElement('li')
|
||||||
|
fund_ph.classList.add('fund-placeholder', 'grid')
|
||||||
|
fund_ph.innerHTML = `
|
||||||
|
<div class="flex-grid justify-start">
|
||||||
|
<div class="placeholder__block"></div>
|
||||||
|
<div class="placeholder__block"></div>
|
||||||
|
<div class="placeholder__block"></div>
|
||||||
|
<div class="placeholder__block"></div>
|
||||||
|
</div>
|
||||||
|
<div class="grid flow-column gap-1">
|
||||||
|
<div class="placeholder__block"></div>
|
||||||
|
<div class="placeholder__block"></div>
|
||||||
|
</div>
|
||||||
|
<div class="placeholder__block justify-self-end"></div>
|
||||||
|
`
|
||||||
|
return fund_ph
|
||||||
|
},
|
||||||
|
investmentCard(details) {
|
||||||
|
const {
|
||||||
|
floId,
|
||||||
|
amountInvested,
|
||||||
|
netValue,
|
||||||
|
fundId,
|
||||||
|
hasMatured = false,
|
||||||
|
allowsEarlyWithdrawal = false,
|
||||||
|
} = details
|
||||||
|
const isRedeemable = hasMatured || allowsEarlyWithdrawal
|
||||||
|
return html`
|
||||||
|
<li class="fund-investor" id=${`${fundId}_${floId}`}>
|
||||||
|
<div class="grid">
|
||||||
|
<span class="label">FLO address</span>
|
||||||
|
<span class="value flo-id">${floId}</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex gap-1-5">
|
||||||
|
<div class="transaction-column">
|
||||||
|
<span class="label">Invested</span>
|
||||||
|
<span class="value amount-invested">${formatAmount(amountInvested[preferredCurrency], preferredCurrency)}</span>
|
||||||
|
</div>
|
||||||
|
<div class="transaction-column">
|
||||||
|
<span class="label">Present value</span>
|
||||||
|
<span class="value net-value" style="color: var(--green)">${formatAmount(netValue[preferredCurrency], preferredCurrency)}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<button class="button fund-investor__redeem" ?disabled=${!isRedeemable}>Redeem</button>
|
||||||
|
</li>
|
||||||
|
`
|
||||||
|
},
|
||||||
|
closedInvestmentCard(details) {
|
||||||
|
const {
|
||||||
|
floId,
|
||||||
|
amountInvested,
|
||||||
|
fundId,
|
||||||
|
BTC_net,
|
||||||
|
endDate,
|
||||||
|
finalAmount,
|
||||||
|
USD_net,
|
||||||
|
payment_refRef
|
||||||
|
} = details
|
||||||
|
return html`
|
||||||
|
<li class="fund-investor" id=${`${fundId}_${floId}`}>
|
||||||
|
<div class="flex align-items-center space-between w-100">
|
||||||
|
<span class="tag">Closed: ${bobsFund.dateFormat(endDate)}</span>
|
||||||
|
</div>
|
||||||
|
<div class="grid">
|
||||||
|
<span class="label">FLO address</span>
|
||||||
|
<span class="value flo-id">${floId}</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex gap-1-5">
|
||||||
|
<div class="transaction-column">
|
||||||
|
<span class="label">Invested</span>
|
||||||
|
<span class="value amount-invested">${formatAmount(amountInvested[preferredCurrency], preferredCurrency)}</span>
|
||||||
|
</div>
|
||||||
|
<div class="transaction-column">
|
||||||
|
<span class="label">Withdrawn amount</span>
|
||||||
|
<span class="value net-value" style="color: var(--green)">${formatAmount(finalAmount[preferredCurrency], preferredCurrency)}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex gap-1-5 align-center space-between w-100">
|
||||||
|
<div class="transaction-column">
|
||||||
|
<a href=${`${floBlockchainAPI.current_server}tx/${payment_refRef}`} target="_blank">See withdrawal transaction</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
`
|
||||||
|
},
|
||||||
|
investmentCard(details) {
|
||||||
|
const {
|
||||||
|
floId,
|
||||||
|
amountInvested,
|
||||||
|
netValue,
|
||||||
|
fundId,
|
||||||
|
hasMatured = false,
|
||||||
|
allowsEarlyWithdrawal = false,
|
||||||
|
} = details
|
||||||
|
const isRedeemable = hasMatured || allowsEarlyWithdrawal
|
||||||
|
return html`
|
||||||
|
<li class="fund-investor" id=${`${fundId}_${floId}`}>
|
||||||
|
<div class="grid">
|
||||||
|
<span class="label">FLO address</span>
|
||||||
|
<span class="value flo-id">${floId}</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex gap-1-5">
|
||||||
|
<div class="transaction-column">
|
||||||
|
<span class="label">Invested</span>
|
||||||
|
<span class="value amount-invested">${formatAmount(amountInvested[preferredCurrency], preferredCurrency)}</span>
|
||||||
|
</div>
|
||||||
|
<div class="transaction-column">
|
||||||
|
<span class="label">Present value</span>
|
||||||
|
<span class="value net-value" style="color: var(--green)">${formatAmount(netValue[preferredCurrency], preferredCurrency)}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<button class="button fund-investor__redeem" ?disabled=${!isRedeemable}>Redeem</button>
|
||||||
|
</li>
|
||||||
|
`
|
||||||
|
},
|
||||||
|
fundBlock(details) {
|
||||||
|
let {
|
||||||
|
fundTxs,
|
||||||
|
startDate,
|
||||||
|
endDate,
|
||||||
|
baseUsd,
|
||||||
|
baseBtc,
|
||||||
|
tapouts,
|
||||||
|
totalInvestment,
|
||||||
|
totalNet,
|
||||||
|
investorsFrag
|
||||||
|
} = details
|
||||||
|
const tapoutsPoints = tapouts.map((tapout, index) => {
|
||||||
|
const duration = `${bobsFund.dateFormat(tapout.start)} to ${bobsFund.dateFormat(tapout.end)}`
|
||||||
|
return html`
|
||||||
|
<li class="tapout-point grid">
|
||||||
|
<span class="label">Tapout ${index + 1}</span>
|
||||||
|
<span class="value">${duration}</span>
|
||||||
|
</li>`;
|
||||||
|
})
|
||||||
|
const renderedFundTxs = fundTxs.map((tx, index) => {
|
||||||
|
return html`<a href=${`${floBlockchainAPI.current_server}tx/${tx.txid}`} target="_blank">Transaction ${index + 1}</a>`
|
||||||
|
})
|
||||||
|
|
||||||
|
return html.node`
|
||||||
|
<li class="fund-block">
|
||||||
|
<h4 class="start-date">${startDate} Fund</h4>
|
||||||
|
<div class="fund-block__details margin-bottom-3r">
|
||||||
|
<div class="grid">
|
||||||
|
<span class="label">End date</span>
|
||||||
|
<span class="value end-date">${bobsFund.dateFormat(endDate)}</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-wrap gap-1">
|
||||||
|
<div class="grid">
|
||||||
|
<span class="label">Initial BTC value</span>
|
||||||
|
<span class="value base-btc">${formatAmount(baseBtc[preferredCurrency], preferredCurrency)}</span>
|
||||||
|
</div>
|
||||||
|
<div class="grid">
|
||||||
|
<span class="label">Base USD rate</span>
|
||||||
|
<span class="value base-usd">${baseUsd.toLocaleString(`en-US`, { style: 'currency', currency: 'INR' })}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-wrap gap-1">
|
||||||
|
<div class="grid">
|
||||||
|
<span class="label">Total investment</span>
|
||||||
|
<span class="value total-investment">${formatAmount(totalInvestment[preferredCurrency], preferredCurrency)}</span>
|
||||||
|
</div>
|
||||||
|
<div class="grid">
|
||||||
|
<span class="label">Total present value</span>
|
||||||
|
<span class="value net-value" style="color: var(--green)">${formatAmount(totalNet[preferredCurrency], preferredCurrency)}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
${tapoutsPoints.length ? html`
|
||||||
|
<div class="grid">
|
||||||
|
<span class="value margin-bottom-0-5r">Tapouts</span>
|
||||||
|
<ul class="tapout-list">${tapoutsPoints}</ul>
|
||||||
|
</div>` : ''}
|
||||||
|
<div class="grid">
|
||||||
|
<span class="label">Fund transactions</span>
|
||||||
|
<div class="flex gap-0-5 flex-wrap">${renderedFundTxs}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="grid">
|
||||||
|
<h4 class="margin-bottom-0-5r">Investors</h4>
|
||||||
|
<ul class="investors-list grid">${investorsFrag}</ul>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
let preferredCurrency
|
let preferredCurrency
|
||||||
|
|
||||||
@ -618,7 +940,7 @@
|
|||||||
const triggerDimensions = trigger.getBoundingClientRect()
|
const triggerDimensions = trigger.getBoundingClientRect()
|
||||||
getRef(target).setAttribute('style', `top: ${triggerDimensions.top + triggerDimensions.height + document.documentElement.scrollTop}px; right: calc(${window.innerWidth - triggerDimensions.right}px - 1.5rem)`)
|
getRef(target).setAttribute('style', `top: ${triggerDimensions.top + triggerDimensions.height + document.documentElement.scrollTop}px; right: calc(${window.innerWidth - triggerDimensions.right}px - 1.5rem)`)
|
||||||
}
|
}
|
||||||
getRef(target).classList.remove('hide-completely')
|
getRef(target).classList.remove('hidden')
|
||||||
getRef(target).animate([
|
getRef(target).animate([
|
||||||
{ transform: 'translateY(-1rem)', opacity: 0 },
|
{ transform: 'translateY(-1rem)', opacity: 0 },
|
||||||
{ transform: 'translateY(0)', opacity: 1 },
|
{ transform: 'translateY(0)', opacity: 1 },
|
||||||
@ -636,13 +958,13 @@
|
|||||||
], options)
|
], options)
|
||||||
.onfinish = () => {
|
.onfinish = () => {
|
||||||
isDropdownOpen = false
|
isDropdownOpen = false
|
||||||
getRef(target).classList.add('hide-completely')
|
getRef(target).classList.add('hidden')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function showPage(target) {
|
function showPage(target) {
|
||||||
document.querySelector('.page:not(.hide-completely)')?.classList.add('hide-completely')
|
document.querySelector('.page:not(.hidden)')?.classList.add('hidden')
|
||||||
getRef(target).classList.remove('hide-completely')
|
getRef(target).classList.remove('hidden')
|
||||||
if (target === 'home_page') {
|
if (target === 'home_page') {
|
||||||
clearAddedInvestors()
|
clearAddedInvestors()
|
||||||
getRef("create_fund_form").reset()
|
getRef("create_fund_form").reset()
|
||||||
@ -655,32 +977,32 @@
|
|||||||
getRef('get_fund_private_key').value = ''
|
getRef('get_fund_private_key').value = ''
|
||||||
}
|
}
|
||||||
if (target === 'loading_page' || target === 'error_page') {
|
if (target === 'loading_page' || target === 'error_page') {
|
||||||
getRef('main_header').classList.add('hide-completely')
|
getRef('main_header').classList.add('hidden')
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
getRef('main_header').classList.remove('hide-completely')
|
getRef('main_header').classList.remove('hidden')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getRef('search_investor').addEventListener('input', debounce(() => {
|
getRef('search_investor').addEventListener('input', debounce(() => {
|
||||||
document.querySelectorAll('.fund-block').forEach(block => {
|
document.querySelectorAll('.fund-block').forEach(block => {
|
||||||
block.querySelectorAll('.fund-investor').forEach(child => {
|
block.querySelectorAll('.fund-investor').forEach(child => {
|
||||||
if (child.dataset.floId.toLowerCase().includes(getRef('search_investor').value.trim().toLowerCase())) {
|
if (child.id.toLowerCase().includes(getRef('search_investor').value.trim().toLowerCase())) {
|
||||||
child.classList.remove('hide-completely')
|
child.classList.remove('hidden')
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
child.classList.add('hide-completely')
|
child.classList.add('hidden')
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
if (Array.from(block.querySelectorAll('.fund-investor')).every(elem => elem.classList.contains('hide-completely'))) {
|
if (Array.from(block.querySelectorAll('.fund-investor')).every(elem => elem.classList.contains('hidden'))) {
|
||||||
block.classList.add('hide-completely')
|
block.classList.add('hidden')
|
||||||
} else {
|
} else {
|
||||||
block.classList.remove('hide-completely')
|
block.classList.remove('hidden')
|
||||||
}
|
}
|
||||||
if (Array.from(getRef('fund_list').children).every(elem => elem.classList.contains('hide-completely'))) {
|
if (Array.from(getRef('fund_list').children).every(elem => elem.classList.contains('hidden'))) {
|
||||||
document.getElementById('fund_list__empty-state')?.classList.remove('hide-completely')
|
document.getElementById('fund_list__empty-state')?.classList.remove('hidden')
|
||||||
} else {
|
} else {
|
||||||
document.getElementById('fund_list__empty-state')?.classList.add('hide-completely')
|
document.getElementById('fund_list__empty-state')?.classList.add('hidden')
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}, 100))
|
}, 100))
|
||||||
@ -716,28 +1038,28 @@
|
|||||||
|
|
||||||
getRef('fund_creation_toggle').addEventListener('change', e => {
|
getRef('fund_creation_toggle').addEventListener('change', e => {
|
||||||
if (e.target.checked) {
|
if (e.target.checked) {
|
||||||
getRef('fund_details_form').classList.add('hide-completely')
|
getRef('fund_details_form').classList.add('hidden')
|
||||||
getRef('fund_details_form').querySelectorAll('input').forEach(input => input.disabled = true)
|
getRef('fund_details_form').querySelectorAll('input').forEach(input => input.disabled = true)
|
||||||
getRef('create_fund_button').classList.add('hide-completely')
|
getRef('create_fund_button').classList.add('hidden')
|
||||||
getRef('add_investors_button').classList.remove('hide-completely')
|
getRef('add_investors_button').classList.remove('hidden')
|
||||||
getRef('fund_selector_container').classList.remove('hide-completely')
|
getRef('fund_selector_container').classList.remove('hidden')
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
getRef('fund_details_form').classList.remove('hide-completely')
|
getRef('fund_details_form').classList.remove('hidden')
|
||||||
getRef('create_fund_button').classList.remove('hide-completely')
|
getRef('create_fund_button').classList.remove('hidden')
|
||||||
getRef('fund_details_form').querySelectorAll('input').forEach(input => input.disabled = false)
|
getRef('fund_details_form').querySelectorAll('input').forEach(input => input.disabled = false)
|
||||||
getRef('add_investors_button').classList.add('hide-completely')
|
getRef('add_investors_button').classList.add('hidden')
|
||||||
getRef('fund_selector_container').classList.add('hide-completely')
|
getRef('fund_selector_container').classList.add('hidden')
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
getRef('tapout_toggle').addEventListener('change', e => {
|
getRef('tapout_toggle').addEventListener('change', e => {
|
||||||
if (!e.target.checked) {
|
if (!e.target.checked) {
|
||||||
getRef('tapout_container').classList.add('hide-completely')
|
getRef('tapout_container').classList.add('hidden')
|
||||||
getRef('tapout_container').querySelectorAll('input').forEach(input => input.disabled = true)
|
getRef('tapout_container').querySelectorAll('input').forEach(input => input.disabled = true)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
getRef('tapout_container').classList.remove('hide-completely')
|
getRef('tapout_container').classList.remove('hidden')
|
||||||
getRef('tapout_container').querySelectorAll('input').forEach(input => input.disabled = false)
|
getRef('tapout_container').querySelectorAll('input').forEach(input => input.disabled = false)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -752,8 +1074,8 @@
|
|||||||
|
|
||||||
/* getRef('term_selector').addEventListener('change', e => {
|
/* getRef('term_selector').addEventListener('change', e => {
|
||||||
const floID = e.detail.value
|
const floID = e.detail.value
|
||||||
getRef('fund_selector').querySelectorAll('.fund-option').forEach(option => option.classList.add('hide-completely'))
|
getRef('fund_selector').querySelectorAll('.fund-option').forEach(option => option.classList.add('hidden'))
|
||||||
getRef('fund_selector').querySelector(`.fund-option[data-flo-id="${floID}"]`)?.classList.remove('hide-completely')
|
getRef('fund_selector').querySelector(`.fund-option[data-flo-id="${floID}"]`)?.classList.remove('hidden')
|
||||||
}) */
|
}) */
|
||||||
|
|
||||||
getRef('refresh_button').addEventListener("click", refresh);
|
getRef('refresh_button').addEventListener("click", refresh);
|
||||||
@ -798,12 +1120,12 @@
|
|||||||
let f = bobsFund.parse(funds[k].map(a => a.data));
|
let f = bobsFund.parse(funds[k].map(a => a.data));
|
||||||
// console.info(f);
|
// console.info(f);
|
||||||
let startDate = new Date(f.start_date).getTime()
|
let startDate = new Date(f.start_date).getTime()
|
||||||
const tapouts = {}
|
let tapouts = []
|
||||||
if (f.tapoutInterval)
|
if (f.tapoutInterval)
|
||||||
f.tapoutInterval.forEach((i, k) => {
|
tapouts = f.tapoutInterval.map((interval, index) => {
|
||||||
let ts = bobsFund.dateAdder(startDate, i),
|
const start = bobsFund.dateAdder(startDate, interval)
|
||||||
te = bobsFund.dateAdder(ts, f.topoutWindow);
|
const end = bobsFund.dateAdder(start, f.topoutWindow)
|
||||||
tapouts[`Tapout ${k + 1}`] = `${bobsFund.dateFormat(ts)} to ${bobsFund.dateFormat(te)}`
|
return { start, end }
|
||||||
})
|
})
|
||||||
const fundObj = {
|
const fundObj = {
|
||||||
fundTxs: funds[k],
|
fundTxs: funds[k],
|
||||||
@ -816,7 +1138,8 @@
|
|||||||
},
|
},
|
||||||
tapouts,
|
tapouts,
|
||||||
}
|
}
|
||||||
const isRedeemable = new Date(fundObj.endDate) < new Date()
|
const hasMatured = new Date(fundObj.endDate) < new Date()
|
||||||
|
const allowsEarlyWithdrawal = tapouts.some(tapout => new Date(tapout.start) < new Date() && new Date(tapout.end) > new Date())
|
||||||
|
|
||||||
// Creating fund selection options
|
// Creating fund selection options
|
||||||
selectableFunds.push(html`
|
selectableFunds.push(html`
|
||||||
@ -831,8 +1154,8 @@
|
|||||||
const investorsFrag = []
|
const investorsFrag = []
|
||||||
let total_invested = total_net = 0;
|
let total_invested = total_net = 0;
|
||||||
for (let investor in f.investments) {
|
for (let investor in f.investments) {
|
||||||
let amount = f.investments[investor].amount,
|
const { amount, closed } = f.investments[investor]
|
||||||
netVal = bobsFund.calcNetValue(f.BTC_base, BTC_current, f.USD_base, USD_current, amount, f.fee);
|
let netVal = bobsFund.calcNetValue(f.BTC_base, BTC_current, f.USD_base, USD_current, amount, f.fee);
|
||||||
const obj = {
|
const obj = {
|
||||||
fundId: k,
|
fundId: k,
|
||||||
floId: investor,
|
floId: investor,
|
||||||
@ -844,11 +1167,13 @@
|
|||||||
inr: netVal.toFixed(2),
|
inr: netVal.toFixed(2),
|
||||||
usd: (netVal / USD_current).toFixed(2),
|
usd: (netVal / USD_current).toFixed(2),
|
||||||
},
|
},
|
||||||
isRedeemable,
|
hasMatured,
|
||||||
|
allowsEarlyWithdrawal,
|
||||||
}
|
}
|
||||||
total_invested += amount;
|
total_invested += amount;
|
||||||
total_net += netVal;
|
total_net += netVal;
|
||||||
if (f.investments[investor].closed) {
|
if (closed) {
|
||||||
|
console.log(closed)
|
||||||
/* TODO: UI: render closing data
|
/* TODO: UI: render closing data
|
||||||
if closed, netVal should not be displayed
|
if closed, netVal should not be displayed
|
||||||
f.investments[investor].closed -> Object {
|
f.investments[investor].closed -> Object {
|
||||||
@ -861,9 +1186,16 @@
|
|||||||
i: index of the txid (of closing tx) ie, funds[k][i].txid
|
i: index of the txid (of closing tx) ie, funds[k][i].txid
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
obj.finalAmount = {
|
||||||
|
inr: closed.amountFinal.toFixed(2),
|
||||||
|
usd: (closed.amountFinal / closed.USD_net).toFixed(2),
|
||||||
|
}
|
||||||
|
investorsFrag.push(render.closedInvestmentCard({ ...obj, ...closed }))
|
||||||
|
floGlobals.investments[`${k}_${investor}`] = { amountInvested: obj.amountInvested, netValue: obj.finalAmount }
|
||||||
|
} else {
|
||||||
|
investorsFrag.push(render.investmentCard(obj))
|
||||||
|
floGlobals.investments[`${k}_${investor}`] = { amountInvested: obj.amountInvested, netValue: obj.netValue }
|
||||||
}
|
}
|
||||||
floGlobals.investments[`${k}_${investor}`] = { amountInvested: obj.amountInvested, netValue: obj.netValue }
|
|
||||||
investorsFrag.push(render.investorCard(obj))
|
|
||||||
}
|
}
|
||||||
fundObj.totalInvestment = {
|
fundObj.totalInvestment = {
|
||||||
inr: total_invested.toFixed(2),
|
inr: total_invested.toFixed(2),
|
||||||
@ -969,7 +1301,30 @@
|
|||||||
}).catch(error => console.error(error))
|
}).catch(error => console.error(error))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
getRef('fund_list').addEventListener('click', e => {
|
||||||
|
if (e.target.closest('.fund-investor__redeem')) {
|
||||||
|
const button = e.target.closest('.fund-investor__redeem')
|
||||||
|
floGlobals.redeemId = button.closest('.fund-investor').id.split('_')
|
||||||
|
const [fundId, investorId] = floGlobals.redeemId
|
||||||
|
renderElem(getRef('redeem__id'), html`<div class='label'>Investor address</div> <strong class="value">${investorId}</strong>`)
|
||||||
|
openPopup('redeem_popup')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
getRef('redeem_private_key_button').addEventListener('click', e => {
|
||||||
|
buttonLoader('redeem_private_key_button', true)
|
||||||
|
const privKey = getRef('redeem_private_key').value
|
||||||
|
const [fundId, investorId] = floGlobals.redeemId
|
||||||
|
floExchangeAPI.closeBobsFundInvestment(fundId, investorId, privKey).then(result => {
|
||||||
|
console.log(result)
|
||||||
|
showChildElement(getRef('redeem_process'), 1, { entry: slideInLeft, exit: slideOutLeft });
|
||||||
|
}).catch(error => {
|
||||||
|
getRef('redeem_failed_message').textContent = error.message
|
||||||
|
showChildElement(getRef('redeem_process'), 2, { entry: slideInLeft, exit: slideOutLeft });
|
||||||
|
console.error(error)
|
||||||
|
}).finally(() => {
|
||||||
|
buttonLoader('redeem_private_key_button', false)
|
||||||
|
})
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
2
scripts/components.min.js
vendored
2
scripts/components.min.js
vendored
File diff suppressed because one or more lines are too long
@ -4,7 +4,7 @@
|
|||||||
const exchangeAPI = EXPORTS;
|
const exchangeAPI = EXPORTS;
|
||||||
|
|
||||||
const DEFAULT = {
|
const DEFAULT = {
|
||||||
marketID: floGlobals.marketID || "FMxYC7gYZhouzqtHZukGnPiQ8nvG4CMzXM",
|
marketID: floGlobals.marketID || "FKAEdnPfjXLHSYwrXQu377ugN4tXU7VGdf",
|
||||||
marketApp: "exchange"
|
marketApp: "exchange"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user