58 Commits
did-1 ... DID-8

Author SHA1 Message Date
DwCay
9820692cd9 Добавлен адресс аккаунта совершившего транзакцию 2022-07-13 15:39:20 +03:00
DwCay
5eb4ee16c0 Удален ValidationLogStore 2022-07-13 14:31:27 +03:00
DwCay
bc364d1b85 Исправлен нейминг в store и transactionsStore. Возвращены иконки юзеров на страницу ValidationLog 2022-07-13 14:30:11 +03:00
DwCay
8489bc375c Интеграция страницы ValidationLog с сервером 2022-07-12 19:21:39 +03:00
DuCay
7ad29e8fe0 Merge pull request #34 from franze6/DID-6
Refactoring method saveDataRegistration in store
2022-07-11 11:16:42 +03:00
DwCay
0fb5764a70 Refactoring method saveDataRegistration in store 2022-07-11 11:15:53 +03:00
DuCay
5ebc965a2a Merge pull request #33 from franze6/DID-6
Refactoring in Onboarding steps
2022-07-08 21:24:21 +03:00
DuCay
138047fa10 Merge branch 'master' into DID-6 2022-07-08 21:24:04 +03:00
DwCay
a271da7bf9 Refactoring in Onboarding steps 2022-07-08 21:20:09 +03:00
Kirill Andrusyak
79784cbcee Merge pull request #32 from franze6/DID-7
Создана форма изменения параметров профиля, добавлен функционал для изменения и добавления параметров
2022-07-08 16:32:18 +03:00
Daria Golova
596c44aac3 changed strange IIFE function 2022-07-07 10:19:31 +03:00
Daria Golova
5d17137815 made sending data 2022-07-06 20:22:48 +03:00
Daria Golova
18bf373508 changed the names of the methods 2022-07-06 19:38:09 +03:00
Daria Golova
944c9989e9 fix seed 2022-07-06 19:33:27 +03:00
Daria Golova
202989f374 agreed on form to change and add 2022-07-06 19:33:27 +03:00
Daria Golova
f21d10f830 added prop key, made update form 2022-07-06 19:33:27 +03:00
DuCay
c8604a56ac Merge pull request #31 from franze6/DID-6
Changing data in store to array
2022-07-06 19:27:56 +03:00
DwCay
2d0ae35cc8 Changing data in store to array 2022-07-06 19:27:26 +03:00
DuCay
76f942b90f Merge pull request #30 from franze6/DID-6
Change methods in store
2022-07-06 18:52:22 +03:00
DwCay
f0e0d9479d Change methods in store 2022-07-06 18:51:57 +03:00
DuCay
3403289e0a Merge pull request #29 from franze6/DID-6
New naming for store
2022-07-06 12:59:44 +03:00
DwCay
25fddec6e8 New naming for store 2022-07-06 12:58:53 +03:00
DuCay
1d0cb45024 Merge pull request #28 from franze6/DID-6
Fix naming in store
2022-07-06 12:46:06 +03:00
DwCay
222850dfd9 Fix naming in store 2022-07-06 12:44:53 +03:00
Kirill Andrusyak
8f225752cf Merge pull request #27 from franze6/DID-6
Add method for delete property account
2022-07-06 12:28:46 +03:00
kandrusyak
038657751a add deploy files 2022-07-05 15:18:36 +03:00
kandrusyak
29d7d6fdb8 change endpoint url 2022-07-05 15:12:22 +03:00
DwCay
e44dfee284 Add method for delete property account 2022-07-04 18:02:34 +03:00
Kirill Andrusyak
0f455f126d Merge pull request #26 from franze6/DID-5
Интеграция таблицы страницы Profile с сервером
2022-07-04 10:10:03 +03:00
Daria Golova
0d4f27660a Merge branch 'DID-5' 2022-07-01 17:27:39 +03:00
Daria Golova
9703371f28 made a reference book 2022-07-01 17:16:09 +03:00
Daria Golova
16ca8a1df2 converted user data into Map object 2022-07-01 16:03:21 +03:00
Daria Golova
e883b190a7 converted user data into Map object 2022-07-01 16:01:20 +03:00
Daria Golova
85897a8efe changed name of the method in store.js 2022-06-30 14:50:59 +03:00
Daria Golova
5f85d1696a integrated received data into table 2022-06-30 14:42:59 +03:00
Daria Golova
1c539e5255 made userDataStore 2022-06-30 14:42:59 +03:00
DuCay
bcfc018560 Merge pull request #25 from franze6/DID-4
Did 4
2022-06-30 13:35:58 +03:00
DwCay
e175ca0295 fix naming for post method 2022-06-30 13:35:07 +03:00
DwCay
bac246eac2 fix label name for post request 2022-06-30 13:17:10 +03:00
DwCay
f65c99e86a fix store 2022-06-29 19:35:06 +03:00
DwCay
63439b2da1 Add method post encrypt auth data 2022-06-29 18:47:49 +03:00
Kirill Andrusyak
1d9368d200 Merge pull request #24 from franze6/DID-3
Доработка формы создания поля
2022-06-28 17:01:22 +03:00
kandrusyak
3a4ed9daf9 auth 2022-06-28 16:38:05 +03:00
Daria Golova
54ccd3ed9f fix popup hint 2022-06-23 18:52:19 +03:00
Daria Golova
fe1105e9d6 delete useEffect 2022-06-23 15:28:29 +03:00
Daria Golova
95cc2ac1e0 fix property field, added default value of seed 2022-06-23 15:21:08 +03:00
Daria Golova
b4516ef18e made a popup hint 2022-06-22 19:36:58 +03:00
kandrusyak
d617de75b5 router fix 2022-06-22 14:53:31 +03:00
Kirill Andrusyak
83e5e39d3c Merge pull request #21 from franze6/DID-2
Создание fetch wrapper
2022-06-21 11:47:58 +03:00
Kirill Andrusyak
f89d59e7df Merge branch 'master' into DID-2 2022-06-21 11:47:49 +03:00
Kirill Andrusyak
c944644db0 Merge pull request #23 from franze6/DID-1
Did 1
2022-06-21 11:44:57 +03:00
DwCay
bfdddee46a Add method for get passPhrase and generation hex for account logo 2022-06-18 16:50:32 +03:00
Daria Golova
f209ee5f5f added token availability check 2022-06-16 16:05:48 +03:00
Daria Golova
9bef3d9311 fix authorization by token 2022-06-16 15:25:25 +03:00
Daria Golova
632b98a81a added authorization by token 2022-06-16 14:30:41 +03:00
Daria Golova
81f5ec2741 fix methods 2022-06-15 14:36:23 +03:00
Daria Golova
3fcda54070 fix wrapper 2022-06-15 14:21:39 +03:00
Daria Golova
49aff14a80 create fetch wrapper 2022-06-14 13:53:28 +03:00
27 changed files with 893 additions and 560 deletions

1
.gitignore vendored
View File

@@ -1,2 +1,3 @@
# dependencies
/node_modules
.idea

15
Dockerfile Normal file
View File

@@ -0,0 +1,15 @@
FROM node:16-alpine AS builder
WORKDIR /front
COPY . .
RUN npm install
RUN npm run build
FROM nginx:1.21.6-alpine as runner
COPY ./deploy/nginx.conf /etc/nginx/nginx.conf
COPY --from=builder /front/build /var/www/html
EXPOSE 8080

33
deploy/nginx.conf Normal file
View File

@@ -0,0 +1,33 @@
worker_processes 1;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
keepalive_timeout 65;
gzip_static on;
server {
listen 8080;
server_name localhost;
charset utf-8;
location / {
root /var/www/html;
try_files $uri /index.html;
etag on;
expires max;
add_header Cache-Control public;
location = /index.html {
expires 0;
add_header Cache-Control "no-cache, public, must-revalidate, proxy-revalidate";
}
}
}
}

19
package-lock.json generated
View File

@@ -12580,6 +12580,25 @@
"integrity": "sha512-bRuZp3C0itgLKHu/VNxi66DN/XVkQG7xtoBVWxpvC5FhAqbOCP21+nPhULjnzEqd7xBMybp6KwytdUpZKEgpIQ==",
"requires": {}
},
"mobx": {
"version": "6.6.0",
"resolved": "https://registry.npmjs.org/mobx/-/mobx-6.6.0.tgz",
"integrity": "sha512-MNTKevLH/6DShLZcmSL351+JgiJPO56A4GUpoiDQ3/yZ0mAtclNLdHK9q4BcQhibx8/JSDupfTpbX2NZPemlRg=="
},
"mobx-react": {
"version": "7.5.0",
"resolved": "https://registry.npmjs.org/mobx-react/-/mobx-react-7.5.0.tgz",
"integrity": "sha512-riHu0XZJA6f64L1iXZoAaDjVt6suYoy8I2HIfuz2tX3O4FFaAe4lVA2CoObttmUQTTFPM7j3Df6T4re0cHkghQ==",
"requires": {
"mobx-react-lite": "^3.4.0"
}
},
"mobx-react-lite": {
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/mobx-react-lite/-/mobx-react-lite-3.4.0.tgz",
"integrity": "sha512-bRuZp3C0itgLKHu/VNxi66DN/XVkQG7xtoBVWxpvC5FhAqbOCP21+nPhULjnzEqd7xBMybp6KwytdUpZKEgpIQ==",
"requires": {}
},
"moment": {
"version": "2.29.3",
"resolved": "https://registry.npmjs.org/moment/-/moment-2.29.3.tgz",

View File

@@ -2,7 +2,7 @@ import React, { useEffect } from 'react';
import {
Routes,
Route,
useLocation
useLocation,
} from 'react-router-dom';
import './css/style.scss';

3
src/api/node.js Normal file
View File

@@ -0,0 +1,3 @@
import {fetchWrapper} from '../shared/fetchWrapper';
export const getNodeInfo = (headers) => fetchWrapper.get('node/info/', headers)

View File

@@ -1,12 +1,14 @@
import React, { useState, useRef, useEffect } from 'react';
import {observer} from "mobx-react-lite";
import { Link } from 'react-router-dom';
import Transition from '../utils/Transition';
import {registrationStore} from "../store/store";
import {generateSvgAvatar} from "../images/GenerateOnboardingSvg/GenerateSvg";
import UserAvatar from '../images/user-avatar-32.png';
function DropdownProfile({
const DropdownProfile = observer(({
align
}) {
})=>{
const [dropdownOpen, setDropdownOpen] = useState(false);
@@ -43,7 +45,7 @@ function DropdownProfile({
onClick={() => setDropdownOpen(!dropdownOpen)}
aria-expanded={dropdownOpen}
>
<img className="w-8 h-8 rounded-full" src={localStorage.getItem('svgAvatar') || UserAvatar} width="32" height="32" alt="User" />
<img className="w-8 h-8 rounded-full" src={generateSvgAvatar(registrationStore.pubKey) || UserAvatar} width="32" height="32" alt="User" />
<div className="flex items-center truncate">
<span className="truncate ml-2 text-sm font-medium group-hover:text-slate-800">Acme Inc.</span>
<svg className="w-3 h-3 shrink-0 ml-1 fill-current text-slate-400" viewBox="0 0 12 12">
@@ -95,6 +97,6 @@ function DropdownProfile({
</Transition>
</div>
)
}
})
export default DropdownProfile;

View File

@@ -35,13 +35,10 @@ function createBlob(options) {
return path + "z";
}
export var generateSvgAvatar = (function () {
return function (seed, raw) {
let pubKey = localStorage.getItem('svgKey') || Math.floor(Math.random()*65535*65535).toString(16) + Math.floor(Math.random()*65535*65535).toString(16) + Math.floor(Math.random()*65535*65535).toString(16) + Math.floor(Math.random()*65535*65535).toString(16) + Math.floor(Math.random()*65535*65535).toString(16) + Math.floor(Math.random()*65535*65535).toString(16) + Math.floor(Math.random()*65535*65535).toString(16) + Math.floor(Math.random()*65535*65535).toString(16);
export var generateSvgAvatar = ( function () {
return function (publicKey, seed, raw) {
let pubKey = publicKey || Math.floor(Math.random()*65535*65535).toString(16) + Math.floor(Math.random()*65535*65535).toString(16) + Math.floor(Math.random()*65535*65535).toString(16) + Math.floor(Math.random()*65535*65535).toString(16) + Math.floor(Math.random()*65535*65535).toString(16) + Math.floor(Math.random()*65535*65535).toString(16) + Math.floor(Math.random()*65535*65535).toString(16) + Math.floor(Math.random()*65535*65535).toString(16);
//pubKey = "73f47d4929d7b2b6598ca4999d52567f9bb5aef3e353e0a66b468096db6e4e88"
if (!localStorage.getItem('svgKey')) {
localStorage.setItem('svgKey', `${pubKey}`)
}
let particles = [];
let gradients = ['#000000'];
let defs = [];

View File

@@ -1,7 +1,7 @@
import React from 'react'
import ReactDOM from 'react-dom'
import {Buffer} from "buffer";
import { BrowserRouter as Router } from 'react-router-dom'
import { HashRouter as Router } from 'react-router-dom'
import App from './App'
globalThis.Buffer = Buffer

View File

@@ -1,4 +1,4 @@
import React, {useEffect, useState} from 'react';
import React, {useState} from 'react';
import Sidebar from '../partials/Sidebar';
import Header from '../partials/Header';
@@ -19,9 +19,6 @@ import DashboardCard10 from '../partials/dashboard/DashboardCard10';
import DashboardCard11 from '../partials/dashboard/DashboardCard11';
function Dashboard() {
useEffect(() => {
localStorage.setItem('svgKey', '')
}, [])
const [sidebarOpen, setSidebarOpen] = useState(false);
return (

View File

@@ -4,8 +4,14 @@ import { Link } from 'react-router-dom';
import OnboardingImage from '../images/onboarding-image.jpg';
import OnboardingDecoration from '../images/auth-decoration.png';
import Logo from "../images/logo.png";
import {observer} from "mobx-react-lite";
import {passphrase} from "@liskhq/lisk-client";
import {registrationStore} from "../store/store";
const Onboarding1 = observer(()=>{
let phrase = passphrase.Mnemonic.generateMnemonic()
registrationStore.savePassPhrase(phrase)
function Onboarding1() {
return (
<main className="bg-white">
@@ -127,6 +133,6 @@ function Onboarding1() {
</main>
);
}
})
export default Onboarding1;

View File

@@ -1,7 +1,7 @@
import React, {useEffect, useState} from 'react';
import React, {useState} from 'react';
import { Link } from 'react-router-dom';
import { observer } from "mobx-react-lite";
import { registrationStore } from "../store/registrationStore";
import { registrationStore } from "../store/store";
import OnboardingImage from '../images/onboarding-image.jpg';
import OnboardingDecoration from '../images/auth-decoration.png';
@@ -11,9 +11,9 @@ const Onboarding2 = observer(()=>{
const [dataRegistration, setDataRegistration] = useState(
{
first_name: '',
last_name: '',
second_name: '',
gender: '',
date_birth: '',
birthdate: '',
}
)
const [fillingForm, setFillingForm] = useState(false)
@@ -24,31 +24,22 @@ const Onboarding2 = observer(()=>{
...dataRegistration,
[event.target.id]: newValue
})
if(!Object.keys(dataRegistration).find(item=>!dataRegistration[item])) {
setFillingForm(true)
}
}
const saveStoreRegistration = ()=>{
Object.keys(dataRegistration).forEach(item=>{
let element=document.getElementById(item)
if(dataRegistration[item]) {
element.style.borderColor=""
} else {
element.style.borderColor="red"
if(fillingForm) {
registrationStore.saveDataRegistration(Object.keys(dataRegistration).map(item=>{
return{
key: `${item}`,
value: dataRegistration[item]
}
})
if(Object.keys(dataRegistration).find(item=>!dataRegistration[item])) {
return
} else {
setFillingForm(true)
}))
}
registrationStore.saveDataRegistration(dataRegistration)
}
useEffect(()=>{
if(fillingForm===true) {
document.getElementById("signup").click()
}
},[fillingForm])
return (
<main className="bg-white">
@@ -107,8 +98,8 @@ const Onboarding2 = observer(()=>{
<input id="first_name" onChange={(event)=>saveValueChange(event)} className="form-input w-full" type="text" />
</div>
<div>
<label className="block text-sm font-medium mb-1" htmlFor="last_name">Last name <span className="text-rose-500">*</span></label>
<input id="last_name" onChange={(event)=>saveValueChange(event)} className="form-input w-full" type="text" />
<label className="block text-sm font-medium mb-1" htmlFor="second_name">Last name <span className="text-rose-500">*</span></label>
<input id="second_name" onChange={(event)=>saveValueChange(event)} className="form-input w-full" type="text" />
</div>
<div>
<label className="block text-sm font-medium mb-1" htmlFor="gender">Gender <span className="text-rose-500">*</span></label>
@@ -119,8 +110,8 @@ const Onboarding2 = observer(()=>{
</select>
</div>
<div>
<label className="block text-sm font-medium mb-1" htmlFor="date_birth">Date of birth <span className="text-rose-500">*</span></label>
<input id="date_birth" onChange={(event)=>saveValueChange(event)} className="form-input w-full" type="date" autoComplete="on" />
<label className="block text-sm font-medium mb-1" htmlFor="birthdate">Date of birth <span className="text-rose-500">*</span></label>
<input id="birthdate" onChange={(event)=>saveValueChange(event)} className="form-input w-full" type="date" autoComplete="on" />
</div>
</div>
<div className="flex items-center justify-between mt-6">

View File

@@ -1,23 +1,36 @@
import React, {useEffect, useState} from 'react';
import React, { useState} from 'react';
import { Link } from 'react-router-dom';
import {generateSvgAvatar} from "../images/GenerateOnboardingSvg/GenerateSvg";
import Logo from "../images/logo.png";
import {registrationStore} from "../store/store";
import { passphrase } from "@liskhq/lisk-client";
function Onboarding3() {
const [passPhrase, setPassPhrase] = useState('')
function getPassPhrase() {
const [passPhrase, setPassPhrase] = useState(convertPhraseToArray(registrationStore.passPhrase))
function generatePassPhrase() {
let phrase = passphrase.Mnemonic.generateMnemonic()
setPassPhrase(phrase)
registrationStore.savePassPhrase(phrase)
setPassPhrase(convertPhraseToArray(registrationStore.passPhrase))
}
useEffect(()=>{
return ()=>{
localStorage.setItem('svgAvatar', generateSvgAvatar())
function savePassPhraseInStore (copiedPhrase) {
let phrasePaste = convertPhraseToArray(copiedPhrase.trim())
if(phrasePaste.length===12) {
registrationStore.savePassPhrase(copiedPhrase.trim())
setPassPhrase(phrasePaste)
} else {
return false
}
}, [])
}
function pastePassPhrase() {
navigator.clipboard.readText().then(res=>savePassPhraseInStore(res))
}
function convertPhraseToArray(phrase) {
return phrase.split(' ').map((item, index) => ({str:item, id:index }))
}
return (
<main className="bg-white">
@@ -73,21 +86,21 @@ function Onboarding3() {
<h1 className="text-3xl text-slate-800 font-bold mb-12">Company information </h1>
{/* htmlForm */}
<div className="grid grid-cols-4 gap-y-2.5 gap-[18px] mb-14">
{passPhrase.split(' ').map(tag => (
<button key={tag} className="min-w-93px w-24 min-h-26px h-26px bg-slate-100 text-slate-500 cursor-pointer hover:bg-blue-100 hover:text-blue-600 rounded-full text-center px-2.5">
<span className="text-sm font-medium">{tag}</span>
{passPhrase.map(tag => (
<button key={tag.id} className="min-w-93px w-24 min-h-26px h-26px bg-slate-100 text-slate-500 cursor-pointer hover:bg-blue-100 hover:text-blue-600 rounded-full text-center px-2.5">
<span className="text-sm font-medium">{tag.str}</span>
</button>
))}
</div>
<div className="flex pl-7 gap-x-5">
<button className="btn pl-9 pr-16 border-slate-200 hover:border-slate-300 text-slate-600">
<button onClick={()=>pastePassPhrase()} className="btn pl-9 pr-16 border-slate-200 hover:border-slate-300 text-slate-600">
<svg className="w-4 h-4 fill-current text-slate-400 shrink-0 mb-0.5" viewBox="0 0 16 16">
<path
d="M11.7.3c-.4-.4-1-.4-1.4 0l-10 10c-.2.2-.3.4-.3.7v4c0 .6.4 1 1 1h4c.3 0 .5-.1.7-.3l10-10c.4-.4.4-1 0-1.4l-4-4zM4.6 14H2v-2.6l6-6L10.6 8l-6 6zM12 6.6L9.4 4 11 2.4 13.6 5 12 6.6z"></path>
</svg>
<span className="ml-2">Paste</span>
</button>
<button onClick={()=>getPassPhrase()} className="btn pr-11 pl-7 border-slate-200 hover:border-slate-300 text-rose-500">
<button onClick={()=>generatePassPhrase()} className="btn pr-11 pl-7 border-slate-200 hover:border-slate-300 text-rose-500">
<svg className="mb-0.5" width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M14.5744 5.66943L13.1504 7.09343C13.4284 7.44043 13.6564 7.75743 13.8194 8.00043C13.0594 9.13043 10.9694 11.8204 8.25836 11.9854L6.44336 13.8004C6.93936 13.9244 7.45736 14.0004 8.00036 14.0004C12.7074 14.0004 15.7444 8.71643 15.8714 8.49243C16.0424 8.18843 16.0434 7.81643 15.8724 7.51243C15.8254 7.42743 15.3724 6.63143 14.5744 5.66943Z" fill="#F43F5E"/>
<path fillRule="evenodd" clipRule="evenodd" d="M1.00038 16.0002C0.744375 16.0002 0.488375 15.9022 0.293375 15.7072C-0.0976249 15.3162 -0.0976249 14.6842 0.292375 14.2942L2.82138 11.7653C1.17238 10.2913 0.198375 8.61425 0.128375 8.48925C-0.0416249 8.18625 -0.0426249 7.81725 0.126375 7.51425C0.251375 7.28925 3.24537 2.00025 8.00037 2.00025C9.33138 2.00025 10.5154 2.43125 11.5484 3.03825L14.2934 0.29325C14.6844 -0.09775 15.3164 -0.09775 15.7074 0.29325C16.0984 0.68425 16.0984 1.31625 15.7074 1.70725L1.70738 15.7072C1.51238 15.9022 1.25638 16.0002 1.00038 16.0002ZM8.00037 4.00025C5.14637 4.00025 2.95837 6.83525 2.18138 7.99925C2.55938 8.56225 3.28538 9.51025 4.24038 10.3463L6.07438 8.51225C6.02938 8.34825 6.00037 8.17825 6.00037 8.00025C6.00037 6.89525 6.89537 6.00025 8.00037 6.00025C8.17838 6.00025 8.34838 6.02925 8.51237 6.07425L10.0784 4.50825C9.43738 4.20125 8.74237 4.00025 8.00037 4.00025Z" fill="#F43F5E"/>
@@ -113,7 +126,7 @@ function Onboarding3() {
{/* Image */}
<div className="flex flex-col items-center h-full w-full hidden md:block absolute top-0 bottom-0 right-0 md:w-1/2" aria-hidden="true">
<div className="flex mt-40 flex-col items-center gap-2.5">
<img className="object-cover object-center" src={generateSvgAvatar()} width="493px" height="493px" alt="Onboarding" />
<img className="object-cover object-center" src={generateSvgAvatar(registrationStore.pubKey)} width="493px" height="493px" alt="Onboarding" />
<span className="text-sm">Your generated Digital ID</span>
</div>
</div>

View File

@@ -1,35 +1,29 @@
import React, {useEffect, useState} from 'react';
import React, {useState} from 'react';
import { Link } from 'react-router-dom';
import {generateSvgAvatar} from "../images/GenerateOnboardingSvg/GenerateSvg";
import Logo from "../images/logo.png";
import {observer} from "mobx-react-lite";
import { registrationStore } from "../store/registrationStore";
import { registrationStore } from "../store/store";
const Onboarding4 = observer(()=>{
const [checkBoxesSelected, setCheckBoxesSelected] = useState(false)
function validateCheckBox () {
let checkBoxes=[...document.getElementsByClassName("form-checkbox")]
if(checkBoxes.find(item=>item.checked===false)) {
return
} else {
setCheckBoxesSelected(true)
const [checkBoxesSelected, setCheckBoxesSelected] = useState([])
function createAccount () {
if(checkBoxesSelected.length===2) {
registrationStore.pushAccountData()
}
}
useEffect(()=>{
if(checkBoxesSelected===true) {
document.getElementById("link-dashboard").click()
function saveCheckBoxesValues(e) {
const { id, checked } = e.target
setCheckBoxesSelected([...checkBoxesSelected, id])
if (!checked) {
setCheckBoxesSelected(checkBoxesSelected.filter(item=>item!==id))
}
}
},[checkBoxesSelected])
useEffect(()=>{
return ()=>{
localStorage.setItem('svgAvatar', generateSvgAvatar())
}
}, [])
const firstNameAccount = registrationStore.accountData.length && registrationStore.accountData.find(item=>item.key==="first_name").value
return (
<main className="bg-white">
@@ -86,20 +80,20 @@ const Onboarding4 = observer(()=>{
<circle className="text-emerald-100" cx="32" cy="32" r="32" />
<path className="text-emerald-500" d="m28.5 41-8-8 3-3 5 5 12-12 3 3z" />
</svg>
<h1 className="text-3xl text-slate-800 font-bold mb-8">{`Nice to meet you, ${registrationStore.accountData().first_name} 🙌`}</h1>
<button onClick={()=>validateCheckBox()} className="btn px-6 bg-indigo-500 hover:bg-indigo-600 text-white">
<Link id="link-dashboard" to={checkBoxesSelected && "/dashboard"}>Go To Profile -&gt;</Link>
<h1 className="text-3xl text-slate-800 font-bold mb-8">{firstNameAccount ? `Nice to meet you, ${firstNameAccount} 🙌` : 'Please, go back step 2'}</h1>
<button onClick={()=>createAccount()} className="btn px-6 bg-indigo-500 hover:bg-indigo-600 text-white">
<Link id="link-dashboard" to={checkBoxesSelected.length===2 && "/dashboard"}>Go To Profile -&gt;</Link>
</button>
</div>
<div className="flex items-center justify-between">
<div className="mr-1">
<label className="flex items-center">
<input type="checkbox" className="form-checkbox" />
<input id="checkbox-1" onChange={(e)=>saveCheckBoxesValues(e)} type="checkbox" className="form-checkbox" />
<span className="text-sm ml-2">I understand that Idntty cannot recover pass phrase</span>
</label>
<label className="flex items-center">
<input type="checkbox" className="form-checkbox" />
<input id="checkbox-2" onChange={(e)=>saveCheckBoxesValues(e)} type="checkbox" className="form-checkbox" />
<div className="text-sm ml-2">
I <Link className="text-indigo-500 hover:text-indigo-600 underline" to="/">store my pharse</Link> very carefuly
</div>
@@ -117,7 +111,7 @@ const Onboarding4 = observer(()=>{
{/* Image */}
<div className="flex flex-col items-center h-full w-full hidden md:block absolute top-0 bottom-0 right-0 md:w-1/2" aria-hidden="true">
<div className="flex mt-40 flex-col items-center gap-2.5">
<img className="object-cover object-center" src={generateSvgAvatar()} width="493px" height="493px" alt="Onboarding" />
<img className="object-cover object-center" src={generateSvgAvatar(registrationStore.pubKey)} width="493px" height="493px" alt="Onboarding" />
<span className="text-sm">Your generated Digital ID</span>
</div>
</div>

View File

@@ -1,34 +1,89 @@
import React, { useState } from 'react';
import { userDataStore } from '../../store/userDataStore';
import { registrationStore } from "../../store/store";
import Sidebar from '../../partials/Sidebar';
import { observer } from 'mobx-react-lite';
import Header from '../../partials/Header';
import ProfileTable from '../../partials/digitalId/ProfileTable';
import Image from '../../images/transactions-image-04.svg';
import ProfileIcon from '../../images/profile-icon.svg';
import Avatar01 from '../../images/avatar-01.jpg';
import Avatar02 from '../../images/avatar-02.jpg';
import Avatar03 from '../../images/avatar-03.jpg';
function Profile () {
const Profile = observer (() => {
const [sidebarOpen, setSidebarOpen] = useState(false);
const [buttonPanelOpen, setButtonPanelOpen] = useState(true);
const [removePanelOpen, setRemovePanelOpen] = useState(false);
const [changePanelOpen, setChangePanelOpen] = useState(false);
const [toggle, setToggle] = useState(true);
const [addPanelOpen, setAddPanelOpen] = useState(false);
const [updatePanelOpen, setUpdatePanelOpen] = useState(false);
const [selectedItems, setSelectedItems] = useState([]);
const defaultValues = {
label: '',
value: '',
seed: Math.floor(Math.random() * 90000000000000000000)
};
const initialPropertyValues = ['First name', 'Second name', 'Birthdate', 'Gender', 'National doctype', 'National doc id', 'National doc issue date', 'National doc expiry date'];
const [propertyValues, setPropertyValues] = useState([]);
const [updatedValues, setUpdatedValues] = useState([defaultValues]);
const [addedValues, setAddedValues] = useState(defaultValues);
const openHint = () => {
if (!addedValues.label) {
setPropertyValues(initialPropertyValues);
}
}
const changeAddedValues = (value, field) => {
setAddedValues((prevState) => (
field !== 'seed' ? {
...prevState,
[field]: value
} : {
...prevState,
[field]: +value,
}))
};
const changeUpdatedValues = (value, field, key) => {
setUpdatedValues((prevState) =>
prevState.map((elem) => (
(elem.key === key && field !== 'seed') ? {
...elem,
[field]: value,
} :
(elem.key === key) ? {
...elem,
[field]: +value,
} : elem
))
)
};
const closeHint = (element) => {
changeAddedValues(element, 'label');
setPropertyValues([]);
}
const handleSelectedItems = (selectedItems) => {
setSelectedItems([...selectedItems]);
setUpdatedValues(userDataStore.decryptedData.filter(({ key }) => selectedItems.includes(key))
.map(elem => (
(!elem.seed) ? {
...elem,
seed: Math.floor(Math.random() * 90000000000000000000)
}: elem)));
if (selectedItems.length > 0) {
setButtonPanelOpen(false);
setAddPanelOpen(false);
setChangePanelOpen(true);
}
if (removePanelOpen === true) {
if (removePanelOpen === true || updatePanelOpen === true) {
setChangePanelOpen(false);
}
if (selectedItems.length === 0) {
setRemovePanelOpen(false);
setUpdatePanelOpen(false);
setButtonPanelOpen(true);
setChangePanelOpen(false);
}
@@ -39,9 +94,64 @@ function Profile () {
setButtonPanelOpen(false);
}
const cancelAddPanel = () => {
const sendAddedData = () => {
if (!userDataStore.decryptedData.some((element) => element.label === addedValues.label) && (addedValues.seed.toString().length === 20)) {
setAddPanelOpen(false);
setButtonPanelOpen(true);
setAddedValues(defaultValues);
addDataParameters();
}
}
const sendUpdatedData = () => {
setUpdatePanelOpen(false);
changeDataParameters();
setChangePanelOpen(true);
}
const deleteDataParameters = () => {
const changeData = userDataStore.decryptedData.filter(item=>!selectedItems.includes(item.key))
registrationStore.pushAccountData(changeData);
}
const changeInitialArray = () => {
let newArr = [];
userDataStore.decryptedData.map(elem => {
updatedValues.forEach(item => {
if (elem.label === item.label) {
newArr.push({
...elem,
'value': item.value,
'seed': item.seed,
})
}
})
if (!newArr.find(element => element.label === elem.label)) {
newArr.push(elem);
}
})
return newArr;
}
const changeDataParameters = () => {
const updatedData = changeInitialArray();
registrationStore.pushAccountData(updatedData);
}
const addDataParameters = () => {
addedValues.key = addedValues.label.toLowerCase().split(' ').join('_');
registrationStore.pushAccountData(userDataStore.decryptedData.concat(addedValues));
}
const cancelAddPanel = () => {
setAddedValues(defaultValues);
setAddPanelOpen(false);
setButtonPanelOpen(true);
}
const cancelUpdatePanel = () => {
setUpdatePanelOpen(false);
setChangePanelOpen(true);
}
const openRemovePanel = () => {
@@ -49,145 +159,25 @@ function Profile () {
setChangePanelOpen(false);
}
const applyRemovePanel = () => {
setRemovePanelOpen(false);
setButtonPanelOpen(true);
const openUpdatePanel = () => {
setUpdatePanelOpen(true);
setChangePanelOpen(false);
}
const userData = [
{
id: '0',
category: 'General',
validated: true,
blockchained: true,
image: ProfileIcon,
value: 'Dominik',
property: 'First name',
status: 'Completed',
transactions: ['0x7234ABC342342352345', '0x5745DEF342342352345'],
avatars: [Avatar01, Avatar02, Avatar03]
},
{
id: '1',
category: 'General',
validated: true,
blockchained: true,
image: ProfileIcon,
value: 'Lamakani',
property: 'Second name',
status: 'Progress',
transactions: ['0x7234ABC342342352345', '0x5745DEF342342352345'],
avatars: null
},
{
id: '2',
category: 'General',
validated: true,
blockchained: true,
image: ProfileIcon,
value: '05.10.1983',
property: 'Birthdate',
status: 'Incorrect',
transactions: ['0x7234ABC342342352345', '0x5745DEF342342352345'],
avatars: null
},
{
id: '3',
category: 'General',
validated: true,
blockchained: true,
image: ProfileIcon,
value: 'Male',
property: 'Gender',
status: 'Stored',
transactions: ['0x7234ABC342342352345', '0x5745DEF342342352345'],
avatars: null
},
{
id: '4',
category: 'Nationality',
validated: true,
blockchained: true,
image: ProfileIcon,
value: 'United Kindom',
property: 'Residence',
status: 'Completed',
transactions: ['0x7234ABC342342352345', '0x5745DEF342342352345'],
avatars: [Avatar01, Avatar02, Avatar03]
},
{
id: '5',
category: 'Nationality',
validated: true,
blockchained: true,
image: ProfileIcon,
value: 'Passport',
property: 'Document type',
status: 'Progress',
transactions: ['0x7234ABC342342352345', '0x5745DEF342342352345'],
avatars: [Avatar01, Avatar02, Avatar03]
},
{
id: '6',
category: 'Nationality',
validated: true,
blockchained: true,
image: ProfileIcon,
value: 'A123B3143',
property: 'Document ID',
status: 'Incorrect',
transactions: ['0x7234ABC342342352345', '0x5745DEF342342352345'],
avatars: null
},
{
id: '7',
category: 'Nationality',
validated: true,
blockchained: true,
image: ProfileIcon,
value: '05.10.2012',
property: 'Issue date',
status: 'Stored',
transactions: ['0x7234ABC342342352345', '0x5745DEF342342352345'],
avatars: null
},
{
id: '8',
category: 'Nationality',
validated: true,
blockchained: true,
image: ProfileIcon,
value: '05.10.2032',
property: 'Expiry date',
status: 'Stored',
transactions: ['0x7234ABC342342352345', '0x5745DEF342342352345'],
avatars: null
},
{
id: '9',
category: 'Social',
validated: true,
blockchained: true,
image: ProfileIcon,
value: '@lamakani',
property: 'Telegram',
status: 'Completed',
transactions: ['0x7234ABC342342352345', '0x5745DEF342342352345'],
avatars: null
},
{
id: '10',
category: 'Social',
validated: true,
blockchained: true,
image: ProfileIcon,
value: '@lamakani',
property: 'Telegram',
status: 'Progress',
transactions: ['0x7234ABC342342352345', '0x5745DEF342342352345'],
avatars: [Avatar01, Avatar02, Avatar03]
},
]
const applyDataDeletion = () => {
setRemovePanelOpen(false);
setButtonPanelOpen(true);
deleteDataParameters()
}
const handleInput = (text, field) => {
changeAddedValues(text, field);
setPropertyValues(initialPropertyValues);
if (text) {
let reg = new RegExp(`^${text}`, 'img');
setPropertyValues((prevState) => prevState.filter((element) => element.match(reg)));
}
};
return (
<div className="flex h-screen overflow-hidden">
@@ -222,7 +212,7 @@ function Profile () {
</ul>
</div>
{/* Table */}
<ProfileTable selectedItems={handleSelectedItems} userData={userData}/>
<ProfileTable selectedItems={handleSelectedItems} userData={userDataStore.decryptedData}/>
</div>
{/* Left sidebar */}
<div>
@@ -246,22 +236,56 @@ function Profile () {
<div className="flex flex-col gap-y-3">
<div>
<label className="block text-sm font-medium mb-1" htmlFor="mandatory">Property <span className="text-rose-500">*</span></label>
<input id="property" className="form-input w-full" type="text" required />
<input
autoComplete='off'
id="label"
className="form-input w-full"
type="text"
required
onInput={(e) => handleInput(e.target.value, 'label')}
value={addedValues.label}
onClick={openHint}
/>
<div className={`flex flex-col gap-y-2 py-2 pl-2 border border-t-0 border-slate-200 rounded ${(propertyValues.length > 0) || 'hidden'}`}>
<ul>
{propertyValues.map((element, index) => (
<li key={index} onClick={() => closeHint(element)}>{element}</li>
))}
</ul>
</div>
</div>
<div>
<label className="block text-sm font-medium mb-1" htmlFor="mandatory">Value <span className="text-rose-500">*</span></label>
<input id="value" className="form-input w-full" type="text" required />
<input
autoComplete='off'
id="value"
className="form-input w-full"
type="text"
required
onClick={() => setPropertyValues([])}
onChange={(e) => changeAddedValues(e.target.value, 'value')}
value={addedValues.value}
/>
</div>
<div>
<label className="block text-sm font-medium mb-1" htmlFor="mandatory">Seed <span className="text-rose-500">*</span></label>
<input id="seed" className="form-input w-full" type="text" required />
<input
autoComplete='off'
id="seed"
className="form-input w-full"
type="number"
required
onClick={() => setPropertyValues([])}
onChange={(e) => changeAddedValues(e.target.value, 'seed')}
value={addedValues.seed}
/>
</div>
</div>
<div className="flex flex-row justify-between pt-[16px] pb-[23px] items-center border-b border-slate-200">
<span className="block text-sm font-medium">Store data on blockchain</span>
<div className="flex items-center">
<div className="form-switch">
<input type="checkbox" id="switch-1" className="sr-only" checked={toggle} onChange={() => setToggle(!toggle)} />
<input type="checkbox" id="blockcheined" className="sr-only" checked={toggle} onChange={() => setToggle(!toggle)} />
<label className="bg-slate-400" htmlFor="switch-1">
<span className="bg-white shadow-sm" aria-hidden="true"></span>
</label>
@@ -278,7 +302,79 @@ function Profile () {
</button>
<button
className="btn-sm bg-indigo-500 hover:bg-indigo-600 text-white"
onClick={cancelAddPanel}
onClick={sendAddedData}
>
Send
</button>
</div>
</div>
{/* Update panel */}
<div className={`${!updatePanelOpen && 'hidden'} bg-white p-5 shadow-lg rounded-sm border border-slate-200 lg:w-72 xl:w-80 mb-11`}>
{updatedValues.map((item, index) => (
<div key={index} className="flex flex-col gap-y-3">
<div>
<label className="block text-sm font-medium mb-1" htmlFor="mandatory">Property <span className="text-rose-500">*</span></label>
<input
id={`${item.key}:label`}
className="form-input w-full"
type="text"
required
onChange={(e) => changeUpdatedValues(e.target.value, 'label', item.key)}
value={item.label}
disabled='disabled'
/>
</div>
<div>
<label className="block text-sm font-medium mb-1" htmlFor="mandatory">Value <span className="text-rose-500">*</span></label>
<input
autoComplete='off'
id={`${item.key}:value`}
className="form-input w-full"
type="text"
required
onChange={(e) => changeUpdatedValues(e.target.value, 'value', item.key)}
value={item.value}
/>
</div>
<div>
<label className="block text-sm font-medium mb-1" htmlFor="mandatory">Seed <span className="text-rose-500">*</span></label>
<input
autoComplete='off'
id={`${item.key}:seed`}
className="form-input w-full"
type="number"
required
onChange={(e) => changeUpdatedValues(e.target.value, 'seed', item.key)}
value={item.seed}
/>
</div>
{(updatedValues[index+1]) ? (
<div className="mt-2 mb-3.5 items-center border-b border-slate-200"></div>
) : null}
</div>
))}
<div className="flex flex-row justify-between pt-[16px] pb-[23px] items-center border-b border-slate-200">
<span className="block text-sm font-medium">Store data on blockchain</span>
<div className="flex items-center">
<div className="form-switch">
<input type="checkbox" id="blockcheined" className="sr-only" checked={toggle} onChange={() => setToggle(!toggle)} />
<label className="bg-slate-400" htmlFor="switch-1">
<span className="bg-white shadow-sm" aria-hidden="true"></span>
</label>
</div>
</div>
</div>
{/* Buttons */}
<div className="flex flex-row justify-end gap-x-2 pt-[18px] pb-[14px] items-end">
<button
className="btn-sm bg-white border-slate-200 hover:bg-slate-50 text-slate-600"
onClick={cancelUpdatePanel}
>
Cansel
</button>
<button
className="btn-sm bg-indigo-500 hover:bg-indigo-600 text-white"
onClick={sendUpdatedData}
>
Send
</button>
@@ -288,8 +384,8 @@ function Profile () {
<div className={`${!removePanelOpen && 'hidden'} bg-white px-5 pt-4 pb-[190px] shadow-lg rounded-sm border border-slate-200 lg:w-72 xl:w-80 mb-12`}>
<h2 className="grow text-base font-semibold text-slate-800 truncate mb-2">Summary</h2>
<div className="flex flex-col">
{userData.filter(({ id }) => selectedItems.includes(id)).map(item => (
<span key={item.id} className="text-sm font-normal text-slate-600 py-3 border-b border-slate-200">{item.property}</span>
{userDataStore.decryptedData.filter(({ key }) => selectedItems.includes(key)).map(item => (
<span key={item.label} className="text-sm font-normal text-slate-600 py-3 border-b border-slate-200">{item.label}</span>
))}
</div>
<div className="flex flex-row justify-between pt-[16px] pb-7 items-center">
@@ -306,7 +402,7 @@ function Profile () {
<div className="flex flex-row justify-end gap-x-2 pt-[20px] pb-[16px] items-end">
<button
className="btn w-full bg-indigo-500 hover:bg-indigo-600 text-white px-[100px] justify-start"
onClick={applyRemovePanel}
onClick={applyDataDeletion}
>
<svg className="w-4 h-4 fill-current shrink-0" viewBox="0 0 16 16">
<path d="m2.457 8.516.969-.99 2.516 2.481 5.324-5.304.985.989-6.309 6.284z" />
@@ -369,7 +465,10 @@ function Profile () {
</svg>
<span className="ml-2">Remove</span>
</button>
<button className="btn w-full border-slate-200 hover:border-slate-300 text-slate-600 px-[100px] justify-start">
<button
className="btn w-full border-slate-200 hover:border-slate-300 text-slate-600 px-[100px] justify-start"
onClick={openUpdatePanel}
>
<svg className="w-4 h-4 fill-rose-500 shrink-0" viewBox="0 0 16 16">
<path d="M14.682 2.318A4.485 4.485 0 0 0 11.5 1 4.377 4.377 0 0 0 8 2.707 4.383 4.383 0 0 0 4.5 1a4.5 4.5 0 0 0-3.182 7.682L8 15l6.682-6.318a4.5 4.5 0 0 0 0-6.364Zm-1.4 4.933L8 12.247l-5.285-5A2.5 2.5 0 0 1 4.5 3c1.437 0 2.312.681 3.5 2.625C9.187 3.681 10.062 3 11.5 3a2.5 2.5 0 0 1 1.785 4.251h-.003Z" />
</svg>
@@ -390,6 +489,6 @@ function Profile () {
</div>
</div>
)
}
})
export default Profile;
export default Profile

View File

@@ -1,70 +1,18 @@
import React, { useState } from 'react';
import {observer} from "mobx-react-lite";
import {transactionsStore} from "../../store/transactionsStore";
import Sidebar from '../../partials/Sidebar';
import Header from '../../partials/Header';
import ValidateTable from "../../partials/validate/ValidateTable";
import ValidatePanel from "../../partials/validate/ValidatePanel";
import ValidateRoadMap from "../../partials/validationlog/ValidateRoadMap";
import {Link} from "react-router-dom";
import User06 from "../../images/user-28-06.jpg";
import User08 from "../../images/user-28-08.jpg";
import User09 from "../../images/user-28-09.jpg";
import User05 from "../../images/user-28-05.jpg";
function Validate () {
const Validate = observer(()=>{
const [sidebarOpen, setSidebarOpen] = useState(false);
const [validatePanelOpen, setValidatePanelOpen] = useState(true);
const validateItems = [
{
id: '40',
name: 'Today',
data: '7234ABC342342352345',
usersImges: [
{
size: 24,
img: User06,
imgId: "343"
},
{
size: 24,
img: User08,
imgId: "345"
},
{
size: 24,
img: User09,
imgId: "321"
},
{
size: 24,
img: User05,
imgId: "387"
},
],
items: [
{
dataSeason: '7234ABC342342352345',
id: '555',
text: 'Second name for',
checked: true
},
{
dataSeason: '7234ABC342342352345',
id: '534',
text: 'Gender name for',
checked: true
},
{
dataSeason: '7234ABC342342352345',
id: '567',
text: 'Document ID name for',
checked: true
},
]
},
];
return (
<div className="flex h-screen overflow-hidden">
{/* Sidebar */}
@@ -110,7 +58,7 @@ function Validate () {
<div className="pb-8 border-b border-zinc-200 mt-[50px]">
<h1 className="text-2xl md:text-3xl text-slate-800 font-bold">Digital ID validation log </h1>
</div>
{validateItems.map(item => {
{transactionsStore.transactionsData.map(item => {
return <ValidateRoadMap season={item} key={item.id}/>
})}
</div>
@@ -120,6 +68,6 @@ function Validate () {
</div>
</div>
)
}
})
export default Validate;

View File

@@ -1,115 +1,14 @@
import React, { useState } from 'react';
import React, {useState} from 'react';
import ValidateRoadMap from "../../partials/validationlog/ValidateRoadMap";
import {transactionsStore} from "../../store/transactionsStore";
import {observer} from "mobx-react-lite";
import Sidebar from '../../partials/Sidebar';
import Header from '../../partials/Header';
import User05 from "../../images/user-28-05.jpg";
import User08 from "../../images/user-28-08.jpg";
import User09 from "../../images/user-28-09.jpg";
import User06 from "../../images/user-28-06.jpg";
import User03 from "../../images/user-28-03.jpg";
import User01 from "../../images/user-28-01.jpg";
function ValidationLog () {
const ValidationLog = observer(()=>{
const [sidebarOpen, setSidebarOpen] = useState(false);
const logItems = [
{
id: '20',
name: 'Today',
data: '7234ABC342342352345',
usersImges: [
{
size: 24,
img: User06,
imgId: "249"
},
{
size: 24,
img: User08,
imgId: "212"
},
{
size: 24,
img: User09,
imgId: "217"
},
{
size: 24,
img: User05,
imgId: "276"
},
],
items: [
{
dataSeason: '7234ABC342342352345',
id: '434',
text: 'Second name',
checked: true
},
{
dataSeason: '7234ABC342342352345',
id: '476',
text: 'First name by',
checked: true
},
{
dataSeason: '7234ABC342342352345',
id: '422',
text: 'Document name by',
checked: true
},
]
},
{
id: '30',
name: 'Last Week',
data: '7234ABC342342352345',
usersImges: [
{
size: 24,
img: User06,
imgId: "145"
},
{
size: 24,
img: User08,
imgId: "182"
},
{
size: 24,
img: User09,
imgId: "154"
},
{
size: 24,
img: User05,
imgId: "114"
},
],
items: [
{
dataSeason: '7234ABC342342352345',
id: '654',
text: 'Gender name by',
checked: true
},
{
dataSeason: '7234ABC342342352345',
id: '617',
text: 'Second name Updated',
checked: false
},
{
dataSeason: '7234ABC342342352345',
id: '643',
text: 'Gender name by',
checked: true
},
]
},
]
return (
<div className="flex h-screen overflow-hidden">
{/* Sidebar */}
@@ -129,61 +28,9 @@ function ValidationLog () {
<div className="max-w-3xl m-auto mt-6">
<div className="xl:-translate-x-16 max-w-fit">
{/* PostsID */}
{logItems.map(item => {
return <ValidateRoadMap season={item} key={item.id} />
{transactionsStore.transactionsData.map(item=>{
return <ValidateRoadMap season={item} key={item.id}/>
})}
{/* Post */}
<article className="pt-3">
<div className="xl:flex">
<div className="w-32 shrink-0">
<h2 className="text-xl leading-snug font-bold text-slate-800 xl:leading-7 mb-4 xl:mb-0">Even earlier</h2>
</div>
<div className="grow pb-6 border-b border-slate-200">
<header>
<div className="flex flex-nowrap items-center space-x-2 mb-6">
{/* Avatars */}
<div className="flex shrink-0 -space-x-3 -ml-px">
<a className="block" href="#0">
<img className="rounded-full border-2 border-white box-content" src={User03} width="28" height="28" alt="User 03" />
</a>
<a className="block" href="#0">
<img className="rounded-full border-2 border-white box-content" src={User01} width="28" height="28" alt="User 01" />
</a>
</div>
<div className="text-slate-400">·</div>
</div>
</header>
{/* List */}
<ul className="-my-2">
{/* List item */}
<li className="relative py-2">
<div className="flex items-center mb-1">
<div className="absolute left-0 h-full w-0.5 bg-slate-200 self-start ml-2.5 -translate-x-1/2 translate-y-3" aria-hidden="true"></div>
<div className="absolute left-0 rounded-full bg-white" aria-hidden="true">
<svg className="w-5 h-5 fill-current text-slate-400" viewBox="0 0 20 20">
<path d="M10 18a8 8 0 100-16 8 8 0 000 16zm0 2C4.477 20 0 15.523 0 10S4.477 0 10 0s10 4.477 10 10-4.477 10-10 10z" />
</svg>
</div>
<h3 className="text-lg font-bold text-slate-800 pl-9">Product V1 - Early Access</h3>
</div>
<div className="pl-9">Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.</div>
</li>
{/* List item */}
<li className="relative py-2">
<div className="flex items-center mb-1">
<div className="absolute left-0 rounded-full bg-white" aria-hidden="true">
<svg className="w-5 h-5 fill-current text-slate-400" viewBox="0 0 20 20">
<path d="M10 18a8 8 0 100-16 8 8 0 000 16zm0 2C4.477 20 0 15.523 0 10S4.477 0 10 0s10 4.477 10 10-4.477 10-10 10z" />
</svg>
</div>
<h3 className="text-lg font-bold text-slate-800 pl-9">Web3 Compatibility</h3>
</div>
<div className="pl-9">Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.</div>
</li>
</ul>
</div>
</div>
</article>
</div>
</div>
</div>
@@ -191,6 +38,6 @@ function ValidationLog () {
</div>
</div>
)
}
})
export default ValidationLog;

View File

@@ -2,7 +2,7 @@ import React, { useState } from 'react';
import Sidebar from '../../partials/Sidebar';
import Header from '../../partials/Header';
function Verify () {
const Verify = (() => {
const [sidebarOpen, setSidebarOpen] = useState(false);
const [descriptionOpen, setDescriptionOpen] = useState(false);
@@ -165,6 +165,6 @@ function Verify () {
</div>
</div>
)
}
})
export default Verify;

View File

@@ -1,5 +1,6 @@
import React, {useState, useEffect} from 'react';
import ProfileTableItem from './ProfileTableItem';
import ProfileIcon from '../../images/profile-icon.svg';
function ProfileTable({
selectedItems,
@@ -8,6 +9,13 @@ function ProfileTable({
const [isCheck, setIsCheck] = useState([]);
const defaultData = {
image: ProfileIcon,
status: 'Stored',
transactions: ['0x7234ABC342342352345', '0x5745DEF342342352345'],
avatars: null
}
useEffect(() => {
selectedItems(isCheck);
// eslint-disable-next-line react-hooks/exhaustive-deps
@@ -21,86 +29,124 @@ function ProfileTable({
}
};
const data = {
general:["First name","Second name", "Gender", "Birthdate", "Place of birth"],
nationality:["Nationality", "National ID", "National doctype", "National doc ID", "National doc issue date", "National doc expiry date"],
social:["Telephone", "Twitter", "Facebook", "Instagram", "Youtube", "Wechat", "Tiktok", "Linkedin", "Vk", "Github", "Telegram", "Qq", "Snapchat", "Reddit"]
}
const generalData = userData.filter(elem => data.general.includes(elem.label)),
nationalityData = userData.filter(elem => data.nationality.includes(elem.label)),
sosialData = userData.filter(elem => data.social.includes(elem.label)),
otherData = userData.filter((elem) =>
!data.general.includes(elem.label) && !data.nationality.includes(elem.label) && !data.social.includes(elem.label));
return (
<>
{/* General */}
<div className={`${generalData.length > 0 || 'hidden'}`}>
<h2 className="grow text-base font-semibold text-slate-800 truncate mb-2.5 mt-8">General 🖋</h2>
<div className="overflow-x-auto w-[828px]">
<table className="w-[828px] table-auto w-full">
<tbody className="divide-slate-200 divide-y">
{userData.filter(data => data.category === 'General')
.map(data => {
{generalData.map((data) => {
return (
<ProfileTableItem
key={data.id}
id={data.id}
image={data.image}
value={data.value}
property={data.property}
status={data.status}
transactions={data.transactions}
avatars={data.avatars}
key={data.label}
id={data.key}
image={defaultData.image}
value={data.value.charAt(0).toUpperCase()+data.value.slice(1)}
property={data.label}
status={defaultData.status}
transactions={defaultData.transactions}
avatars={defaultData.avatars}
handleClick={handleClick}
isChecked={isCheck.includes(data.id)}
isChecked={isCheck.includes(data.key)}
/>
)
})
}
})}
</tbody>
</table>
</div>
</div>
{/* Nationality */}
<div className={`${nationalityData.length > 0 || 'hidden'}`}>
<h2 className="grow text-base font-semibold text-slate-800 truncate mb-2.5 mt-8">Nationality 🖋</h2>
<div className="overflow-x-auto w-[828px]">
<table className="w-[828px] table-auto w-full">
<tbody className="text-sm divide-slate-200 divide-y ">
{userData.filter(data => data.category === 'Nationality')
.map(data => {
{nationalityData.map(data => {
return (
<ProfileTableItem
key={data.id}
id={data.id}
image={data.image}
value={data.value}
property={data.property}
status={data.status}
transactions={data.transactions}
avatars={data.avatars}
key={data.label}
id={data.key}
image={defaultData.image}
value={data.value.charAt(0).toUpperCase()+data.value.slice(1)}
property={data.label}
status={defaultData.status}
transactions={defaultData.transactions}
avatars={defaultData.avatars}
handleClick={handleClick}
isChecked={isCheck.includes(data.id)}
isChecked={isCheck.includes(data.key)}
/>
)
})
}
})}
</tbody>
</table>
</div>
</div>
{/* Social */}
<div className={`${sosialData.length > 0 || 'hidden'}`}>
<h2 className="grow text-base font-semibold text-slate-800 truncate mb-2.5 mt-8">Social 🖋</h2>
<div className="overflow-x-auto w-[828px]">
<table className="w-[828px] table-auto w-full">
<tbody className="text-sm divide-slate-200 divide-y ">
{userData.filter(data => data.category === 'Social')
.map(data => {
{sosialData.map(data => {
return (
<ProfileTableItem
key={data.id}
id={data.id}
image={data.image}
value={data.value}
property={data.property}
status={data.status}
transactions={data.transactions}
avatars={data.avatars}
key={data.label}
id={data.key}
image={defaultData.image}
value={data.value.charAt(0).toUpperCase()+data.value.slice(1)}
property={data.label}
status={defaultData.status}
transactions={defaultData.transactions}
avatars={defaultData.avatars}
handleClick={handleClick}
isChecked={isCheck.includes(data.id)}
isChecked={isCheck.includes(data.key)}
/>
)
})
}
})}
</tbody>
</table>
</div>
</div>
{/* Other */}
<div className={`${otherData.length > 0 || 'hidden'}`}>
<h2 className="grow text-base font-semibold text-slate-800 truncate mb-2.5 mt-8">Other 🖋</h2>
<div className="overflow-x-auto w-[828px]">
<table className="w-[828px] table-auto w-full">
<tbody className="text-sm divide-slate-200 divide-y ">
{otherData.map(data => {
return (
<ProfileTableItem
key={data.key}
id={data.key}
image={defaultData.image}
value={data.value}
property={data.label}
status={defaultData.status}
transactions={defaultData.transactions}
avatars={defaultData.avatars}
handleClick={handleClick}
isChecked={isCheck.includes(data.key)}
/>
)
})}
</tbody>
</table>
</div>
</div>
</>
)
}

View File

@@ -9,15 +9,15 @@ function ValidateRoadMap({ season }) {
<article className="pt-3">
<div className="xl:flex">
<div className="w-32 shrink-0">
<h2 className="text-xl leading-snug font-bold text-slate-800 xl:leading-7 mb-4 xl:mb-0">{season.name}</h2>
<h2 className="text-xl leading-snug font-bold text-slate-800 xl:leading-7 mb-4 xl:mb-0">{''}</h2>
</div>
<div className="grow pb-6 border-b border-slate-200">
<div className="grow pb-6">
<header>
<div className="flex flex-nowrap items-center space-x-2 mb-6">
{/* Avatars */}
<div className="flex shrink-0 -space-x-3 -ml-px">
{season.usersImges.map(pic => {
return <ValidationUsersImg key={pic.imgId} image={pic}/>
{season.users_images.map(pic => {
return <ValidationUsersImg image={pic} key={pic.image}/>
})}
</div>
<div className="text-slate-400">·</div>
@@ -26,8 +26,8 @@ function ValidateRoadMap({ season }) {
{/* List */}
<ul className="-my-2">
{/* List item(s) */}
{season.items.map((item, index) => {
return <ValidationSeasonItem key={item.id} length={season.items.length} item={item} index={index}/>
{season.transaction.map((item, index) => {
return <ValidationSeasonItem key={item.label} length={season.transaction.length} item={item} index={index}/>
})}
</ul>
</div>

View File

@@ -5,21 +5,21 @@ function ValidationSeasonItem({ length, item, index }) {
<li className="relative pt-2 pb-2.5">
<div className="flex items-center mb-2.5">
{length-1!==index && <div className="absolute left-0 h-full w-0.5 bg-slate-200 self-start ml-2.5 -translate-x-1/2 translate-y-3" aria-hidden="true"></div>}
<div className={`absolute left-0 rounded-full ${item.checked ? "bg-indigo-500" : "bg-[#FF0000]"}`} aria-hidden="true">
<div className="absolute left-0 rounded-full bg-indigo-500" aria-hidden="true">
<svg className="w-5 h-5 fill-current text-white" viewBox="0 0 20 20">
{item.checked && <path d="M14.4 8.4L13 7l-4 4-2-2-1.4 1.4L9 13.8z"/>}
<path d="M14.4 8.4L13 7l-4 4-2-2-1.4 1.4L9 13.8z"/>
</svg>
</div>
<h3 className="text-lg font-bold text-slate-800 pl-9">
{item.text} {item.checked && <a className="cursor-pointer font-bold text-indigo-500 hover:text-indigo-600 underline hover:no-underline" >{`0x${item.dataSeason}`}</a>}
{`${item.label} by`} <a className="cursor-pointer font-bold text-indigo-500 hover:text-indigo-600 underline hover:no-underline" >{item.address}</a>
</h3>
</div>
<div className="block text-slate-800 w-fit pl-9">
<div className="text-base font-semibold underline mb-[-10px]">{`0x${item.dataSeason}`}</div>
<div className="text-base font-semibold underline mb-[-10px]">{item.transaction_id}</div>
<span className="font-normal text-slate-600 text-[10px]">Transactions ID</span>
</div>
<div className="mb-3.5 block text-slate-800 w-fit pl-9">
<div className="text-base font-semibold underline mb-[-10px]">{item.dataSeason}</div>
<div className="text-base font-semibold underline mb-[-10px]">{item.value}</div>
<span className="font-normal text-slate-600 text-[10px]">Validated data</span>
</div>
<a className="cursor-pointer pl-9 font-normal text-sm text-indigo-500 hover:text-indigo-600">Explore -&gt;</a>

View File

@@ -1,9 +1,10 @@
import React from "react";
function ValidationUsersImg({ image }) {
return (
<a className="block" href="#0">
<img className="rounded-full border-2 border-slate-100 box-content" src={image.img} width={`${image.size}`} alt={image.img} height={`${image.size}`}/>
<a className="block">
<img className="rounded-full border-2 border-slate-100 box-content" src={image.image} width={`${image.size}`} alt={image.image} height={`${image.size}`}/>
</a>
);
}

103
src/shared/fetchWrapper.js Normal file
View File

@@ -0,0 +1,103 @@
import {registrationStore} from '../store/store';
function prepareUrl(url) {
if (url.startsWith('http')) return url;
return `http://3.125.47.101/api/${url}`;
}
function handleRequest(method, url, headers, attempts, token, body) {
return new Promise((resolve, reject) => {
(function internalRequest() {
return request(method, url, headers, token, body)
.then(resolve)
.catch(err => --attempts > 0 ? internalRequest() : reject(err))
})()
})
.then((res) => res.json())
.catch(() => [])
};
/**
* Request
* @param {string} method - method name
* @param {string} url - endpoint url.
* @param {string} token - auth token
* @param {object} body - request body.
* @param {object} headers - request headers
*/
function request(method, url, headers = {}, token, body) {
let controller = new AbortController;
let requestOptions = {};
if (method === 'GET' || method === 'DELETE'){
requestOptions = {
method: method,
headers: {
Authorization: `IDNTTY ${token}`,
...headers
},
signal: controller.signal,
}
};
if (method === 'POST' || method === 'PUT'){
requestOptions = {
method: method,
headers: {
Authorization: `IDNTTY ${token}`,
Accept: 'application/json',
'Content-Type': 'application/json',
...headers
},
body: JSON.stringify(body),
signal: controller.signal,
}
};
if (!token) {
requestOptions.headers.Authorization = null;
}
setTimeout(() => controller.abort(), 3000);
return fetch(prepareUrl(url), requestOptions);
};
function get(url, headers, attempts = 1) {
return handleRequest('GET', url, headers, attempts, null);
}
function getAuth(url, headers, attempts = 1) {
return handleRequest('GET', url, headers, attempts, registrationStore.tokenKey);
}
function del(url, headers, attempts = 1) {
return handleRequest('DELETE', url, headers, attempts, null);
}
function delAuth(url, headers, attempts = 1) {
return handleRequest('DELETE', url, headers, attempts, registrationStore.tokenKey);
}
function post(url, headers, body, attempts = 1) {
return handleRequest('POST', url, headers, attempts, null, body);
}
function postAuth(url, headers, body, attempts = 1) {
return handleRequest('POST', url, headers, attempts, registrationStore.tokenKey, body);
}
function put(url, headers, body, attempts = 1) {
return handleRequest('PUT', url, headers, attempts, null, body);
}
function putAuth(url, headers, body, attempts = 1) {
return handleRequest('PUT', url, headers, attempts, registrationStore.tokenKey, body);
}
export const fetchWrapper = {
get,
del,
post,
put,
getAuth,
delAuth,
postAuth,
putAuth,
baseUrl: ''
};

View File

@@ -1,22 +0,0 @@
import { reaction, makeAutoObservable } from "mobx";
class RegistrationStore {
_accountData = {};
constructor() {
makeAutoObservable(this);
reaction(() => this.accountData, () => this.saveDataRegistration())
};
saveDataRegistration(data) {
this._accountData = data;
};
accountData() {
return this._accountData
};
};
export const registrationStore = new RegistrationStore();

136
src/store/store.js Normal file
View File

@@ -0,0 +1,136 @@
import { reaction, makeAutoObservable } from "mobx";
import {cryptography} from "@liskhq/lisk-client";
import {getNodeInfo} from '../api/node';
import {fetchWrapper} from '../shared/fetchWrapper';
class Store {
_accountData = []
_passPhrase='rocket north inform swift improve fringe sweet crew client canyon bean autumn'
_nodeInfo = {}
_userData = {}
_transactionsInfo = {}
constructor() {
makeAutoObservable(this);
this.fetchNodeInfo()
reaction(() => this.tokenKey, () => this.fetchNewAccountData())
reaction(() => this.tokenKey, () => this.fetchTransactionsInfo())
};
fetchNewAccountData() {
fetchWrapper.getAuth('http://3.125.47.101/api/data/private', {
networkIdentifier: this.nodeInfo.networkIdentifier,
lastBlockID: this.nodeInfo.lastBlockID
}).then((res) => this.userDataFetchChange(res))
}
pushAccountData(data=this.accountData) {
fetchWrapper.postAuth('http://3.125.47.101/api/data/private', {
networkIdentifier: this.nodeInfo.networkIdentifier,
lastBlockID: this.nodeInfo.lastBlockID
}, [...this.encryptAccountData(data)])
.then(()=>this.fetchNewAccountData())
}
fetchTransactionsInfo() {
fetchWrapper.getAuth(`http://3.125.47.101/api/account/transactions/${this.accountMadeTransaction}?moduleID=1001&assetID=11`, {
networkIdentifier: this.nodeInfo.networkIdentifier,
lastBlockID: this.nodeInfo.lastBlockID
})
.then((res)=>this.saveInfoTransactions(res))
}
get accountMadeTransaction() {
return "b444b7ff3118cf2a30cbd54cfcdb8fd5d805017a"
}
userDataFetchChange(res) {
this._userData = res;
}
get userData() {
return this._userData
}
get transactionsInfo() {
return this._transactionsInfo
}
savePassPhrase(phrase) {
this._passPhrase = phrase
}
saveDataRegistration(data) {
this._accountData = data;
};
saveInfoTransactions(transaction) {
this._transactionsInfo = transaction
}
fetchNodeInfo() {
getNodeInfo()
.then((info) => this.fetchNodeInfoSuccess(info))
.catch((err) => this.fetchNodeInfoFailed(err))
}
fetchNodeInfoSuccess(info) {
this._nodeInfo = info.data;
}
fetchNodeInfoFailed(err) {
console.log(err)
}
get passPhrase() {
return 'rocket north inform swift improve fringe sweet crew client canyon bean autumn'
}
get accountData() {
return this._accountData
};
encryptAccountData(data) {
return data.map((item) => {
let value = cryptography.encryptMessageWithPassphrase(cryptography.getRandomBytes(32).toString('hex') + ":" + item.value, this.passPhrase, this.pubKey);
return {
"label": item.key,
"value": value.encryptedMessage,
"value_nonce": value.nonce,
}
})
}
get nodeInfo() {
return this._nodeInfo;
}
get addressAndPubKey() {
return cryptography.getAddressAndPublicKeyFromPassphrase(this.passPhrase);
}
get pubKey() {
return this.addressAndPubKey.publicKey.toString('hex');
}
get address() {
return cryptography.bufferToHex(this.addressAndPubKey.address)
}
get tokenKey() {
const stringToSign = this.nodeInfo.networkIdentifier + this.nodeInfo.lastBlockID;
if(!stringToSign)
return '';
const sign = cryptography.signDataWithPassphrase(Buffer.from(stringToSign, 'hex'), this.passPhrase).toString('hex')
return this.pubKey + ':' +sign
}
};
export const registrationStore = new Store();

View File

@@ -0,0 +1,51 @@
import {makeAutoObservable, reaction} from "mobx";
import {registrationStore} from "./store";
import User05 from "../../src/images/user-28-05.jpg";
import User08 from "../../src/images/user-28-08.jpg";
import User09 from "../../src/images/user-28-09.jpg";
import User06 from "../../src/images/user-28-06.jpg";
const labelMap = {
firstname: 'First name',
secondname: 'Second name',
gender: "Gender",
birthdate: "Birthdate"
};
const usersImages = [User08,User06,User05,User09];
class TransactionsStore {
_transactionsData = [];
constructor() {
makeAutoObservable(this)
reaction(() => ({data: registrationStore.transactionsInfo}), ({data}) => {
this._transactionsData = data.data;
})
}
get transactionsData() {
return this._transactionsData.map(item=>{
return {
id: item.id,
users_images: usersImages.map(image=>{
return {
image: image,
size: 24
}
}),
transaction: item.asset.features.map(asset=>{
return {
transaction_id: item.id,
address: registrationStore.accountMadeTransaction,
value: asset.value,
label: labelMap[asset.label],
}
})
}
})
}
}
export const transactionsStore = new TransactionsStore()

View File

@@ -0,0 +1,53 @@
import { cryptography } from "@liskhq/lisk-client";
import { makeAutoObservable, reaction } from "mobx";
import { registrationStore } from './store';
const labelMap = {
first_name: 'First name',
second_name: 'Second name',
gender: "Gender",
birthdate: "Birthdate",
place_of_birth: "Place of birth",
nationality: "Nationality",
national_id: "National ID",
national_doctype: "National doctype",
national_doc_id: "National doc ID",
national_doc_issue_date: "National doc issue date",
national_doc_expiry_date: "National doc expiry date",
telephone: "Telephone",
twitter: "Twitter",
facebook: "Facebook",
instagram: "Instagram",
youtube: "Youtube",
wechat: "Wechat",
tiktok: "Tiktok",
linkedin: "Linkedin",
vk: "Vk",
github: "Github",
telegram: "Telegram",
qq: "Qq",
snapchat: "Snapchat",
reddit: "Reddit"
};
class UserDataStore{
_data = [];
constructor() {
makeAutoObservable(this);
reaction(() => ({data: registrationStore.userData}), ({data}) => {
this._data = data.data;
})
}
get decryptedData(){
return this._data.map((elem) => ({
...elem,
key: elem.label,
label: labelMap[elem.label],
value: cryptography.decryptMessageWithPassphrase(elem.value, elem.value_nonce, registrationStore.passPhrase, registrationStore.pubKey).split(':')[1]
}))
}
}
export const userDataStore = new UserDataStore();