Compare commits
183 Commits
Verify-Pag
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a2dd48be65 | ||
|
|
bd8268d848 | ||
|
|
4ca691608a | ||
|
|
5939bb4e13 | ||
|
|
68e665804c | ||
|
|
2efc3acd94 | ||
|
|
428153a9d9 | ||
|
|
78f48b240b | ||
|
|
8bf83aaa5b | ||
|
|
e0753a0779 | ||
|
|
9c331789b3 | ||
|
|
3e8a0e2233 | ||
|
|
a8bb75b2f5 | ||
|
|
8e4b6c832e | ||
|
|
0927c0dca5 | ||
|
|
a555d18417 | ||
|
|
ea4d8a4049 | ||
|
|
1448d3e7da | ||
|
|
e07353cd87 | ||
|
|
2210b4ab91 | ||
|
|
8e5c0a3edc | ||
|
|
4f73075cf9 | ||
|
|
b68ef748ca | ||
|
|
200f4f58a7 | ||
|
|
86a6bf013d | ||
|
|
6afa08e5f5 | ||
|
|
3173ec9342 | ||
|
|
c8352e6537 | ||
|
|
9fbc6423d1 | ||
|
|
e4f691ab78 | ||
|
|
446276fadf | ||
|
|
1b574ac347 | ||
|
|
0c7db9cd30 | ||
|
|
fc977cc43a | ||
|
|
0a0151d1dd | ||
|
|
369f0e375c | ||
|
|
79ca03823c | ||
|
|
49f3ee17a0 | ||
|
|
841e82e233 | ||
|
|
2212ea7433 | ||
|
|
f257066d5a | ||
|
|
027bf0d405 | ||
|
|
663cfacf63 | ||
|
|
27ee899402 | ||
|
|
59dd4c9554 | ||
|
|
c659e17344 | ||
|
|
49d86ed74b | ||
|
|
b2d5df9533 | ||
|
|
0eea3d1ea3 | ||
|
|
9686e5245f | ||
|
|
1f306b2dce | ||
|
|
a86dd13e0e | ||
|
|
0e5d7477fc | ||
|
|
f395661480 | ||
|
|
4c334648cb | ||
|
|
344b2c7862 | ||
|
|
826f340e9a | ||
|
|
b4bccf2cba | ||
|
|
7bb1832d4d | ||
|
|
17ac1b04eb | ||
|
|
e4dc1e961e | ||
|
|
fa198054dd | ||
|
|
f31c895b8d | ||
|
|
b7be78cf76 | ||
|
|
6d92fde547 | ||
|
|
03bc841894 | ||
|
|
c24a1fa09d | ||
|
|
57e5dee442 | ||
|
|
188e79caf9 | ||
|
|
e9b21c5c02 | ||
|
|
75464d81f0 | ||
|
|
fcb7d40ca5 | ||
|
|
f27edb97bb | ||
|
|
b75a2349c2 | ||
|
|
37c9feffe1 | ||
|
|
fe6bcf8d0f | ||
|
|
d7488f8ca9 | ||
|
|
ffa92ded10 | ||
|
|
68e94201e0 | ||
|
|
020e45ddce | ||
|
|
8955d846e4 | ||
|
|
d5bc90c818 | ||
|
|
16a2ffca2d | ||
|
|
f932c0bc33 | ||
|
|
da268d7ecc | ||
|
|
736e8fc16b | ||
|
|
774955f131 | ||
|
|
5b20d71a0c | ||
|
|
9714b0add8 | ||
|
|
52eb2a75c1 | ||
|
|
3c77264fae | ||
|
|
429f36b6a6 | ||
|
|
11be69a79b | ||
|
|
911c13cb87 | ||
|
|
1e9830c8d4 | ||
|
|
a8a6355daa | ||
|
|
444c94690b | ||
|
|
67133c5414 | ||
|
|
f58a94bf24 | ||
|
|
9820692cd9 | ||
|
|
2eeb39abc9 | ||
|
|
5eb4ee16c0 | ||
|
|
bc364d1b85 | ||
|
|
8489bc375c | ||
|
|
b9f795c0e4 | ||
|
|
47dfcf347c | ||
|
|
e837f7cc89 | ||
|
|
7ad29e8fe0 | ||
|
|
0fb5764a70 | ||
|
|
5ebc965a2a | ||
|
|
138047fa10 | ||
|
|
a271da7bf9 | ||
|
|
79784cbcee | ||
|
|
596c44aac3 | ||
|
|
5d17137815 | ||
|
|
18bf373508 | ||
|
|
944c9989e9 | ||
|
|
202989f374 | ||
|
|
f21d10f830 | ||
|
|
c8604a56ac | ||
|
|
2d0ae35cc8 | ||
|
|
76f942b90f | ||
|
|
f0e0d9479d | ||
|
|
3403289e0a | ||
|
|
25fddec6e8 | ||
|
|
1d0cb45024 | ||
|
|
222850dfd9 | ||
|
|
8f225752cf | ||
|
|
038657751a | ||
|
|
29d7d6fdb8 | ||
|
|
e44dfee284 | ||
|
|
0f455f126d | ||
|
|
0d4f27660a | ||
|
|
9703371f28 | ||
|
|
16ca8a1df2 | ||
|
|
e883b190a7 | ||
|
|
85897a8efe | ||
|
|
5f85d1696a | ||
|
|
1c539e5255 | ||
|
|
bcfc018560 | ||
|
|
e175ca0295 | ||
|
|
bac246eac2 | ||
|
|
f65c99e86a | ||
|
|
63439b2da1 | ||
|
|
1d9368d200 | ||
|
|
3a4ed9daf9 | ||
|
|
54ccd3ed9f | ||
|
|
fe1105e9d6 | ||
|
|
95cc2ac1e0 | ||
|
|
b4516ef18e | ||
|
|
d617de75b5 | ||
|
|
83e5e39d3c | ||
|
|
f89d59e7df | ||
|
|
c944644db0 | ||
|
|
bfdddee46a | ||
|
|
0da68ddd63 | ||
|
|
f209ee5f5f | ||
|
|
9bef3d9311 | ||
|
|
632b98a81a | ||
|
|
eeaabeebf3 | ||
|
|
81f5ec2741 | ||
|
|
3fcda54070 | ||
|
|
49aff14a80 | ||
|
|
da04efbf80 | ||
|
|
541c5988e9 | ||
|
|
cfa5af78c0 | ||
|
|
fc4d9fb897 | ||
|
|
ed5565eb17 | ||
|
|
99512491fa | ||
|
|
24a66478d6 | ||
|
|
9484b0bda9 | ||
|
|
885963be45 | ||
|
|
e144e50a40 | ||
|
|
16f9a52a41 | ||
|
|
5e74f2bc0b | ||
|
|
fa5ddbf64a | ||
|
|
c45b7c5e4d | ||
|
|
606223216f | ||
|
|
c41bed05fd | ||
|
|
b71dccbd0e | ||
|
|
264a908352 | ||
|
|
f74293b1f4 | ||
|
|
095c5e236e |
64
.github/workflows/docker-image.yml
vendored
Normal file
@@ -0,0 +1,64 @@
|
||||
name: Build and deploy
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- 'master'
|
||||
tags:
|
||||
- '*'
|
||||
paths-ignore:
|
||||
- '.github/**'
|
||||
pull_request:
|
||||
branches:
|
||||
- 'master'
|
||||
tags:
|
||||
- '*'
|
||||
paths-ignore:
|
||||
- '.github/**'
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
logLevel:
|
||||
description: 'Log level'
|
||||
required: true
|
||||
default: 'warning'
|
||||
type: choice
|
||||
options:
|
||||
- info
|
||||
- warning
|
||||
- debug
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: self-hosted
|
||||
steps:
|
||||
- name: Get branch data
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v1
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
||||
- name: Build and push image
|
||||
uses: docker/build-push-action@v2
|
||||
with:
|
||||
push: true
|
||||
tags: kandrusyak/blockchain-ui:master
|
||||
deploy:
|
||||
needs: build
|
||||
name: Deploy to host
|
||||
runs-on: self-hosted
|
||||
steps:
|
||||
- name: Get branch data
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Deploying changes
|
||||
uses: appleboy/ssh-action@master
|
||||
with:
|
||||
host: ${{ secrets.SSH_HOST }}
|
||||
username: ${{ secrets.SSH_USERNAME }}
|
||||
password: ${{ secrets.SSH_PASSWORD }}
|
||||
script: |
|
||||
docker login -u ${{ secrets.DOCKERHUB_USERNAME }} -p ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
./update.sh
|
||||
1
.gitignore
vendored
@@ -1,2 +1,3 @@
|
||||
# dependencies
|
||||
/node_modules
|
||||
.idea
|
||||
19
.prettierrc
Normal file
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"arrowParens": "always",
|
||||
"useTabs": false,
|
||||
"tabWidth": 2,
|
||||
"singleQuote": true,
|
||||
"endOfLine": "lf",
|
||||
"jsxBracketSameLine": false,
|
||||
"trailingComma": "es5",
|
||||
"printWidth": 100,
|
||||
"overrides": [
|
||||
{
|
||||
"files": "*.json",
|
||||
"options": {
|
||||
"singleQuote": false,
|
||||
"parser": "json"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
17
Dockerfile
Normal file
@@ -0,0 +1,17 @@
|
||||
FROM node:16-alpine AS builder
|
||||
|
||||
RUN apk --update add --no-cache curl git python3 alpine-sdk bash autoconf libtool automake
|
||||
|
||||
WORKDIR /front
|
||||
|
||||
COPY . .
|
||||
|
||||
RUN npm install
|
||||
RUN npm run build:prod
|
||||
|
||||
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
|
||||
26
README.md
@@ -1,26 +0,0 @@
|
||||
# Mosaic React
|
||||
|
||||
React landing page template designed by Cruip.
|
||||
|
||||
## Project setup
|
||||
```
|
||||
npm install
|
||||
```
|
||||
|
||||
### Compiles and hot-reloads for development
|
||||
```
|
||||
npm run dev
|
||||
```
|
||||
|
||||
### Compiles and minifies for production
|
||||
```
|
||||
npm run build
|
||||
```
|
||||
|
||||
### Customize configuration
|
||||
See [Configuration Reference](https://vitejs.dev/guide/).
|
||||
|
||||
## Support notes
|
||||
We are shipping our templates with a very basic React configuration to let you quickly get into the development process, but we don't discourage you from using any other configuration or framework built on the top of React. So, please note that any request dealing with React (e.g. extra features, customisations, et cetera) is to be considered out of the support scope.
|
||||
|
||||
For more information about what support covers, please see our (FAQs)[https://cruip.com/faq/].
|
||||
33
deploy/nginx.conf
Normal 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";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
BIN
dist/assets/00aab12feba6fab9c8e5cb94b7bab85c.png
vendored
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
dist/assets/0d7b13bc31f623e46ce6d318d72b8fa0.jpg
vendored
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
dist/assets/337193482a6fc165c3e101c4cd45864b.png
vendored
Normal file
|
After Width: | Height: | Size: 17 KiB |
BIN
dist/assets/5bdc905a0d21817d9e9cf280f7464f6d.png
vendored
Normal file
|
After Width: | Height: | Size: 5.8 KiB |
BIN
dist/assets/6e225e2cab53b1738e4fe13130e1ad4b.jpg
vendored
Normal file
|
After Width: | Height: | Size: 916 B |
BIN
dist/assets/9668c24210a4bf2fcbd7bd5570e95795.jpg
vendored
Normal file
|
After Width: | Height: | Size: 44 KiB |
BIN
dist/assets/9c6b3ebd646e88131f55cd0e4de66a67.png
vendored
Normal file
|
After Width: | Height: | Size: 912 B |
BIN
dist/assets/a7c6e3bab1dca3610a3f01816c09b150.png
vendored
Normal file
|
After Width: | Height: | Size: 623 B |
4
dist/assets/adcfdc4f4455c26d9153b599b1475b09.svg
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
<svg width="36" height="36" viewBox="0 0 36 36" xmlns="http://www.w3.org/2000/svg">
|
||||
<circle fill="#0EA5E9" cx="18" cy="18" r="18" />
|
||||
<path d="M18 26a8 8 0 1 1 8-8 8.009 8.009 0 0 1-8 8Zm0-14a6 6 0 1 0 0 12 6 6 0 0 0 0-12Z" fill="#F0F9FF" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 258 B |
BIN
dist/assets/d33927970705d24be4be69220dbc3ad0.jpg
vendored
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
4
dist/assets/d53e2b56cd0cdf928c678711f37177ab.svg
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
<svg width="36" height="36" viewBox="0 0 36 36" xmlns="http://www.w3.org/2000/svg">
|
||||
<circle fill="#6366F1" cx="18" cy="18" r="18" />
|
||||
<path d="M24.446 19.335a2.5 2.5 0 00-3.522 3.194c-.845.63-1.87.97-2.924.971a4.979 4.979 0 01-1.113-.135 4.436 4.436 0 01-1.343 1.682 6.91 6.91 0 006.9-1.165 2.5 2.5 0 002-4.547h.002zM20.431 11.938a2.5 2.5 0 10-.4 2.014 5.027 5.027 0 012.723 3.078c.148-.018.297-.028.446-.03a4.5 4.5 0 011.7.334 7.023 7.023 0 00-4.469-5.396zM14.969 20.25a2.49 2.49 0 00-1.932-1.234A4.624 4.624 0 0113 18.5a4.97 4.97 0 011.348-3.391 4.456 4.456 0 01-.788-2.016A6.989 6.989 0 0011 18.5c.003.391.04.781.11 1.166a2.5 2.5 0 103.859.584z" fill="#EEF2FF" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 683 B |
10
dist/assets/e9b097e399651f55a5ea32dac11e8b48.svg
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
<svg width="36" height="36" viewBox="0 0 36 36" fill="none" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<circle cx="18" cy="18" r="18" fill="#E1E1F7"/>
|
||||
<rect x="6" y="6" width="24" height="24" fill="url(#pattern0)"/>
|
||||
<defs>
|
||||
<pattern id="pattern0" patternContentUnits="objectBoundingBox" width="1" height="1">
|
||||
<use xlink:href="#image0_21_1525" transform="scale(0.0125)"/>
|
||||
</pattern>
|
||||
<image id="image0_21_1525" width="80" height="80" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFAAAABQCAYAAACOEfKtAAAAAXNSR0IArs4c6QAAAERlWElmTU0AKgAAAAgAAYdpAAQAAAABAAAAGgAAAAAAA6ABAAMAAAABAAEAAKACAAQAAAABAAAAUKADAAQAAAABAAAAUAAAAAAx4ExPAAAHHUlEQVR4Ae1bWYwVRRRlwBGXaBRxRQaMGvDDiAG/lCigjHEDE/VHPox8uGCi4o8mij/G6Iea6JcJ0TCSEDVKYhC3EOPglhgMGoMxKswQBRWXuG8snjNTd7xTr+u9qq7q9/pp3eRQ1bfvPffW7br9+r0eJkzIkiuQK5ArkCuQK5ArkCuQK5ArkCuQK5ArkCvw/6pAT5uWOw1xLgQWAWcCUw3+xrgL2ApsAJ4B/gJccixOLAb6gdnACQB1oTxw6Q45G2k+DewFDnhgGDaXA7acAcU6YB8Qw2Pz1vZ4MjJ7TC32d8yfB24B5gLckbQ5AmBxbgC2ACzOfuA2gNILPAroC8CdeitwDjAdeAt4FyDPjYDmoV3XyYnIWBbBwj0AsNVaCW8nKwEWkFgGvAGwqH8C24BBwJbNUGg9eW4HyMEd2w90jXBHvQ9w0Z8Ac4BQuQcOuk3/wPF5oSSwF54fMX8N4MU5Eqi1vIDsuHjuliklM50EvyFAF/ErHJ8LiLBtufNs0XofHtu/o8eXIDoXvQfoS5DJ4eBYAGwCyPsLMBug2G07qi3Wc9dtBHYDNo/4dXzkfecjk+CKxNlwJw0Y7rcjuMmzNgFPRApu13kmsSGMB7nNSp/hbmQbcwfpViahblseixTpuRv5wVbEI35B48Qga7fxEnNqPUY+cqSWX0G42pAutcj5acuC2FKk/wlG7xlDm8f2b+uxPG7wW0JVsgjELFRMGzO3VDzkSiafgomLOy0ZYyPRSSbGFxiL2pMePnrNQ58oSdXC8qDM+1RV8oMh5uNRUXvytI/+e8Vjpp0f5MZ8aIWpHAZu7nLeD2PkYDin4BnJIdUObMdVlQdz2YlSRJ+2FVuOfCak2Dyj2sB/UxVQkjkmMH6IuXDLxRJfn7YVW47ylGDzaJu2zzcjItviggojy6fn65Exzoc/c43lGUkj1Q78zixKdok5TDoIN3dOaNtq+2kmqyQ7MFUBd5qkTk5asvFk080hY4W2rbaXHCXn8VECj1J97Ro2cWcExg8xF+4hOPH3viKZX6SETuvlQgw5bIPUqXbgDhN1ZlD0MOM+Yy4XS7x1e4qOo0svxbR5tK/3PFUBvzQRZ3pHDjeUHbjLctXtqU+59EcZI5tH+7Z9/iwiHgA+rzDydhODb+5iJBVPTA4Nvj9DwwLyfUhVQm7GYCxXe/roNU90rqlaWD7RTo/OyE0g3Izlak8fveZxR2vzmUcQj7tjVYVxyc0YD0fGSMUTmcZ4d3kfwgUKxluUPxI+GS+2qHzali7iL6PNY9H6HaZqYX5Bvx+Q78SMzl89YkVzkPs+4GWL1Kdte5WPi0eZdHb6McLzKp+SII1TDRdfk8bIDDgzp1iehhxS7UBNLEnO0sqSc+EQTqHxbVuxf9xMbB45X3qsooDvmGyuKZ3Vv47CIZxyxqdtxZZjnzmwebRNbeb8eZ9/osY3YMdFZHU8fPnMRy7Oywpz4Ev5WJ6y8Uv5DcCL95znSnmPOq03HGsMR2jbiv06i8fQ1XvgHz3uMYnfXSLVe43vNxinGn/+aDto5npopudFJDSP9q31vB/Z8S+ruICHAjLlgzJ96HtRgJ9t+iAUKXhs3rYeX2YWwYX4Cm2JSwFpQ9vXR695bP9kx1V8CuvkNuiDwPmLsA/9tC2yJ09Xi+wE30WE2rt4U/G4+Ef0Ve/ApsEDT/q0bSBlvHmVBeTD66qIFOlLDpH9mHBX2eLSi53NI/pajj3Iir/MvALsA6SNQt4/0Fb8yPESUObT2OZhTsyNOdZO+HbvWuADQBbPv2FZAywAQnY6bekzAJBD+LZivgzoBXzamTwLAfLILiUXc2Suqd5Igqq8TIbrCmAHIAv9DPOVgLy8wbS0kOMOgO9ahH8Y873Aq4AtzR6qt8B4JyA82zFn7lxDR+RKRNUL4w65CuCVTy3kvBpgDF0AxgsR/r54HbANEB6ugWtpm8xCpE2AJPAh5lcAPUDVwhiMxZgSfzfm3Hm2NGtznlsKaB6uiWurVHgPkjdw32J+EzCp0ojF5Ix5M8AcWEje45YDWljUQa0wc623ebg23h+TC+8TqwG56k9hfnTyKOGEU+CyFpC8nsD8kHCakf8UpHm4Vq45iTAhPkowSX4qXg/UTZYjIfnEfhNz/S6FuTZrZ+5IEc2zEcoyF0O4xkZeVRbva+CsMW39JsyNOTJX7iAtLFKrdhb7Zjxi4z32w5IJ/QbUuXiyoDkmV+a8UJQlRs2zuIT/mAtfITKZO8c09Z/cZXLmT/i6PSVz33YWHt6+nDLReWb0xFxz/skWdnU6Lbn2IilefFv4ie2jF555NkHIMQMVBQvh6IRtqrxb8tTi+2AbKsy25c6bb8VqpbfMGw9bfXvoxt3XuMp4jbNOre6B8aEzQ65ArkCuQK5ArkCuQK5ArkCuQK5ArkCuQK5ArsB/qgL/AIxZGoBhTSTCAAAAAElFTkSuQmCC"/>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.1 KiB |
BIN
dist/assets/f2a7edc970be4aa58ba65c495ab16ed0.png
vendored
Normal file
|
After Width: | Height: | Size: 32 KiB |
BIN
dist/favicon.ico
vendored
Normal file
|
After Width: | Height: | Size: 3.8 KiB |
1
dist/index.html
vendored
Normal file
@@ -0,0 +1 @@
|
||||
<!doctype html><html lang="en"><head><meta charset="UTF-8"><title>React App</title><link rel="icon" href="favicon.ico"><script defer="defer" src="main.3ab1a28d.js"></script></head><body><div id="root"></div><script>function gtag(){dataLayer.push(arguments)}window.dataLayer=window.dataLayer||[],gtag("js",new Date),gtag("config","G-M6E6PDB6Y4")</script><script async src="https://www.googletagmanager.com/gtag/js?id=G-M6E6PDB6Y4"></script></body></html>
|
||||
8
dist/main.3ab1a28d.js
vendored
Normal file
96
dist/main.3ab1a28d.js.LICENSE.txt
vendored
Normal file
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
object-assign
|
||||
(c) Sindre Sorhus
|
||||
@license MIT
|
||||
*/
|
||||
|
||||
/*!
|
||||
Copyright (c) 2018 Jed Watson.
|
||||
Licensed under the MIT License (MIT), see
|
||||
http://jedwatson.github.io/classnames
|
||||
*/
|
||||
|
||||
/*!
|
||||
* The buffer module from node.js, for the browser.
|
||||
*
|
||||
* @author Feross Aboukhadijeh <https://feross.org>
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
/*! https://mths.be/cssesc v3.0.0 by @mathias */
|
||||
|
||||
/*! https://mths.be/punycode v1.3.2 by @mathias */
|
||||
|
||||
/*! ieee754. BSD-3-Clause License. Feross Aboukhadijeh <https://feross.org/opensource> */
|
||||
|
||||
/*! safe-buffer. MIT License. Feross Aboukhadijeh <https://feross.org/opensource> */
|
||||
|
||||
/**
|
||||
* @license qrcode.react
|
||||
* Copyright (c) Paul O'Shannessy
|
||||
* SPDX-License-Identifier: ISC
|
||||
*/
|
||||
|
||||
/**
|
||||
* React Router DOM v6.3.0
|
||||
*
|
||||
* Copyright (c) Remix Software Inc.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE.md file in the root directory of this source tree.
|
||||
*
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
/**
|
||||
* React Router v6.3.0
|
||||
*
|
||||
* Copyright (c) Remix Software Inc.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE.md file in the root directory of this source tree.
|
||||
*
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
/** @license React v0.20.2
|
||||
* scheduler.production.min.js
|
||||
*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/** @license React v16.13.1
|
||||
* react-is.production.min.js
|
||||
*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/** @license React v17.0.2
|
||||
* react-dom.production.min.js
|
||||
*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/** @license React v17.0.2
|
||||
* react.production.min.js
|
||||
*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/** @license URI.js v4.4.1 (c) 2011 Gary Court. License: http://github.com/garycourt/uri-js */
|
||||
|
||||
//! moment.js
|
||||
|
||||
//! moment.js locale configuration
|
||||
3
dist/settings.json
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"API_URL": "https://tn-alpha.idntty.org:8080/api/"
|
||||
}
|
||||
21
index.html
@@ -1,21 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="/src/favicon.svg" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Vite App</title>
|
||||
</head>
|
||||
<body class="font-inter antialiased bg-slate-100 text-slate-600">
|
||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||
<script>
|
||||
if (localStorage.getItem('sidebar-expanded') == 'true') {
|
||||
document.querySelector('body').classList.add('sidebar-expanded');
|
||||
} else {
|
||||
document.querySelector('body').classList.remove('sidebar-expanded');
|
||||
}
|
||||
</script>
|
||||
<div id="root"></div>
|
||||
<script type="module" src="/src/main.jsx"></script>
|
||||
</body>
|
||||
</html>
|
||||
14110
package-lock.json
generated
56
package.json
@@ -2,27 +2,67 @@
|
||||
"name": "mosaic-react",
|
||||
"version": "0.1.0",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "vite build",
|
||||
"preview": "vite preview"
|
||||
"dev": "webpack-dev-server --https",
|
||||
"build:dev": "webpack --mode development --progress",
|
||||
"build:prod": "webpack --mode production --progress"
|
||||
},
|
||||
"dependencies": {
|
||||
"@liskhq/lisk-client": "^5.2.2",
|
||||
"@tailwindcss/forms": "^0.4.0",
|
||||
"buffer": "^6.0.3",
|
||||
"chart.js": "^3.5.0",
|
||||
"chartjs-adapter-moment": "^1.0.0",
|
||||
"classnames": "^2.3.2",
|
||||
"crypto-browserify": "^3.12.0",
|
||||
"mobx": "^6.6.0",
|
||||
"mobx-react-lite": "^3.4.0",
|
||||
"moment": "^2.29.1",
|
||||
"net": "^1.0.2",
|
||||
"os-browserify": "^0.3.0",
|
||||
"path-browserify": "^1.0.1",
|
||||
"prettier": "^2.8.0",
|
||||
"process": "^0.11.10",
|
||||
"qrcode.react": "^3.1.0",
|
||||
"querystring-es3": "^0.2.1",
|
||||
"react": "^17.0.2",
|
||||
"react-country-flag": "^3.0.2",
|
||||
"react-dom": "^17.0.2",
|
||||
"react-flatpickr": "^3.10.7",
|
||||
"react-loader-spinner": "^5.2.0",
|
||||
"react-router-dom": "^6.2.1",
|
||||
"react-transition-group": "^4.4.1"
|
||||
"react-transition-group": "^4.4.1",
|
||||
"sodium-universal": "^3.1.0",
|
||||
"stream-browserify": "^3.0.0",
|
||||
"url": "^0.11.0",
|
||||
"util": "^0.12.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vitejs/plugin-react": "^1.0.7",
|
||||
"autoprefixer": "^10.4.2",
|
||||
"@babel/core": "^7.18.5",
|
||||
"@babel/preset-env": "^7.18.2",
|
||||
"@babel/preset-react": "^7.17.12",
|
||||
"autoprefixer": "^10.4.5",
|
||||
"babel-loader": "^8.2.5",
|
||||
"css-loader": "^6.7.1",
|
||||
"file-loader": "^6.2.0",
|
||||
"html-loader": "^3.1.2",
|
||||
"html-webpack-plugin": "^5.5.0",
|
||||
"postcss": "^8.4.5",
|
||||
"sass": "^1.49.0",
|
||||
"postcss-loader": "^7.0.0",
|
||||
"sass": "^1.52.3",
|
||||
"sass-loader": "^13.0.0",
|
||||
"style-loader": "^3.3.1",
|
||||
"tailwindcss": "^3.0.18",
|
||||
"vite": "^2.7.2"
|
||||
"webpack": "^5.73.0",
|
||||
"webpack-cli": "^4.10.0",
|
||||
"webpack-dev-server": "^4.9.2"
|
||||
},
|
||||
"babel": {
|
||||
"presets": [
|
||||
"@babel/env",
|
||||
"@babel/react"
|
||||
]
|
||||
},
|
||||
"browser": {
|
||||
"fs": false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import tailwind from 'tailwindcss'
|
||||
import autoprefixer from 'autoprefixer'
|
||||
import tailwindConfig from './src/css/tailwind.config.js'
|
||||
const tailwind = require('tailwindcss')
|
||||
const autoprefixer = require('autoprefixer')
|
||||
const tailwindConfig = require('./src/tailwind.config.js')
|
||||
|
||||
export default {
|
||||
module.exports = {
|
||||
plugins: [tailwind(tailwindConfig), autoprefixer],
|
||||
}
|
||||
BIN
public/favicon.ico
Normal file
|
After Width: | Height: | Size: 3.8 KiB |
19
public/index.html
Normal file
@@ -0,0 +1,19 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>React App</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<script>
|
||||
window.dataLayer = window.dataLayer || [];
|
||||
function gtag(){dataLayer.push(arguments);}
|
||||
gtag('js', new Date());
|
||||
|
||||
gtag('config', 'G-M6E6PDB6Y4');
|
||||
</script>
|
||||
<script async src="https://www.googletagmanager.com/gtag/js?id=G-M6E6PDB6Y4"></script>
|
||||
</body>
|
||||
</html>
|
||||
3
public/settings.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"API_URL": "https://tn-alpha.idntty.org:8080/api/"
|
||||
}
|
||||
77
src/App.jsx
@@ -1,70 +1,63 @@
|
||||
import React, { useEffect } from 'react';
|
||||
import {
|
||||
Routes,
|
||||
Route,
|
||||
useLocation
|
||||
} from 'react-router-dom';
|
||||
import { Routes, Route, useLocation } from 'react-router-dom';
|
||||
|
||||
import './css/style.scss';
|
||||
|
||||
import './charts/ChartjsConfig';
|
||||
|
||||
// Import pages
|
||||
import Dashboard from './pages/Dashboard';
|
||||
import Analytics from './pages/Analytics';
|
||||
import Fintech from './pages/Fintech';
|
||||
import ProfileId from './pages/digitalId/ProfileId';
|
||||
import Validate from './pages/digitalId/Validate';
|
||||
import ValidationLog from './pages/digitalId/ValidationLog';
|
||||
import Verify from './pages/digitalId/Verify';
|
||||
import Messages from './pages/Messages';
|
||||
import ButtonPage from './pages/component/ButtonPage';
|
||||
import BadgePage from './pages/component/BadgePage';
|
||||
import AccordionPage from './pages/component/AccordionPage';
|
||||
import Onboarding1 from "./pages/Onboarding1";
|
||||
import Onboarding2 from "./pages/Onboarding2";
|
||||
import Onboarding3 from "./pages/Onboarding3";
|
||||
import Onboarding4 from "./pages/Onboarding4";
|
||||
import SharedData from "./pages/SharedData";
|
||||
import ResetPassword from "./pages/ResetPassword";
|
||||
import Signup from "./pages/Signup";
|
||||
import Signin from "./pages/Signin";
|
||||
|
||||
function App() {
|
||||
import Onboarding1 from './pages/Onboarding1';
|
||||
import Onboarding2 from './pages/Onboarding2';
|
||||
import Onboarding3 from './pages/Onboarding3';
|
||||
import Onboarding4 from './pages/Onboarding4';
|
||||
import SharedData from './pages/SharedData';
|
||||
import SignIn from './pages/SignIn';
|
||||
import { LoadingOverlay } from './components/LoadingOverlay';
|
||||
import { store } from './store/store';
|
||||
import { observer } from 'mobx-react-lite';
|
||||
import Delegates from './pages/services/Delegates';
|
||||
import VPNServers from './pages/services/VPNServers';
|
||||
import VPNPrepare from './pages/services/VPNPrepare';
|
||||
import { NotificationContainer } from './components/NotificationContainer';
|
||||
|
||||
const App = observer(() => {
|
||||
const location = useLocation();
|
||||
useEffect(() => {
|
||||
localStorage.setItem('svgAvatar', '');
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
document.querySelector('html').style.scrollBehavior = 'auto'
|
||||
window.scroll({ top: 0 })
|
||||
document.querySelector('html').style.scrollBehavior = ''
|
||||
document.querySelector('html').style.scrollBehavior = 'auto';
|
||||
window.scroll({ top: 0 });
|
||||
document.querySelector('html').style.scrollBehavior = '';
|
||||
}, [location.pathname]); // triggered on route change
|
||||
|
||||
if (!store.nodeInfo.networkIdentifier) {
|
||||
return <LoadingOverlay />;
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
{store.loading && <LoadingOverlay />}
|
||||
<NotificationContainer />
|
||||
<Routes>
|
||||
<Route exact path="/" element={<Dashboard />} />
|
||||
<Route path="/dashboard/analytics" element={<Analytics />} />
|
||||
<Route path="/dashboard/fintech" element={<Fintech />} />
|
||||
<Route exact path="/" element={<Onboarding1 />} />
|
||||
<Route path="/digitalId/profile-id" element={<ProfileId />} />
|
||||
<Route path="/digitalId/validate" element={<Validate />} />
|
||||
{/*<Route path="/digitalId/validate" element={<Validate />} />*/}
|
||||
<Route path="/digitalId/validation-log" element={<ValidationLog />} />
|
||||
<Route path="/digitalId/verify" element={<Verify />} />
|
||||
<Route path="/messages" element={<Messages />} />
|
||||
<Route path="/onboarding-1" element={<Onboarding1 />} />
|
||||
<Route path="/onboarding-2" element={<Onboarding2 />} />
|
||||
<Route path="/onboarding-3" element={<Onboarding3 />} />
|
||||
<Route path="/onboarding-4" element={<Onboarding4 />} />
|
||||
<Route path="/component/button" element={<ButtonPage />} />
|
||||
<Route path="/shared-data" element={<SharedData />} />
|
||||
<Route path="/component/badge" element={<BadgePage />} />
|
||||
<Route path="/component/accordion" element={<AccordionPage />} />
|
||||
<Route path="/reset-password" element={<ResetPassword />} />
|
||||
<Route path="/signin" element={<Signin />} />
|
||||
<Route path="/signup" element={<Signup />} />
|
||||
<Route path="/services/delegates" element={<Delegates />} />
|
||||
<Route path="/services/vpn" element={<VPNPrepare />} />
|
||||
<Route path="/services/vpn/servers" element={<VPNServers />} />
|
||||
<Route path="/shared-data/:id" element={<SharedData />} />
|
||||
<Route path="/signIn" element={<SignIn />} />
|
||||
</Routes>
|
||||
</>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
export default App;
|
||||
|
||||
3
src/api/node.js
Normal file
@@ -0,0 +1,3 @@
|
||||
import { fetchWrapper } from '../shared/fetchWrapper';
|
||||
|
||||
export const getNodeInfo = (headers) => fetchWrapper.get('node/info/', headers);
|
||||
@@ -1,162 +0,0 @@
|
||||
import React, { useRef, useEffect } from 'react';
|
||||
|
||||
import {
|
||||
Chart, BarController, BarElement, LinearScale, TimeScale, Tooltip, Legend,
|
||||
} from 'chart.js';
|
||||
import 'chartjs-adapter-moment';
|
||||
|
||||
// Import utilities
|
||||
import { tailwindConfig, formatValue } from '../utils/Utils';
|
||||
|
||||
Chart.register(BarController, BarElement, LinearScale, TimeScale, Tooltip, Legend);
|
||||
|
||||
function BarChart01({
|
||||
data,
|
||||
width,
|
||||
height
|
||||
}) {
|
||||
|
||||
const canvas = useRef(null);
|
||||
const legend = useRef(null);
|
||||
|
||||
useEffect(() => {
|
||||
const ctx = canvas.current;
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
const chart = new Chart(ctx, {
|
||||
type: 'bar',
|
||||
data: data,
|
||||
options: {
|
||||
layout: {
|
||||
padding: {
|
||||
top: 12,
|
||||
bottom: 16,
|
||||
left: 20,
|
||||
right: 20,
|
||||
},
|
||||
},
|
||||
scales: {
|
||||
y: {
|
||||
grid: {
|
||||
drawBorder: false,
|
||||
},
|
||||
ticks: {
|
||||
maxTicksLimit: 5,
|
||||
callback: (value) => formatValue(value),
|
||||
},
|
||||
},
|
||||
x: {
|
||||
type: 'time',
|
||||
time: {
|
||||
parser: 'MM-DD-YYYY',
|
||||
unit: 'month',
|
||||
displayFormats: {
|
||||
month: 'MMM YY',
|
||||
},
|
||||
},
|
||||
grid: {
|
||||
display: false,
|
||||
drawBorder: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
plugins: {
|
||||
legend: {
|
||||
display: false,
|
||||
},
|
||||
tooltip: {
|
||||
callbacks: {
|
||||
title: () => false, // Disable tooltip title
|
||||
label: (context) => formatValue(context.parsed.y),
|
||||
},
|
||||
},
|
||||
},
|
||||
interaction: {
|
||||
intersect: false,
|
||||
mode: 'nearest',
|
||||
},
|
||||
animation: {
|
||||
duration: 500,
|
||||
},
|
||||
maintainAspectRatio: false,
|
||||
resizeDelay: 200,
|
||||
},
|
||||
plugins: [{
|
||||
id: 'htmlLegend',
|
||||
afterUpdate(c, args, options) {
|
||||
const ul = legend.current;
|
||||
if (!ul) return;
|
||||
// Remove old legend items
|
||||
while (ul.firstChild) {
|
||||
ul.firstChild.remove();
|
||||
}
|
||||
// Reuse the built-in legendItems generator
|
||||
const items = c.options.plugins.legend.labels.generateLabels(c);
|
||||
items.forEach((item) => {
|
||||
const li = document.createElement('li');
|
||||
li.style.marginRight = tailwindConfig().theme.margin[4];
|
||||
// Button element
|
||||
const button = document.createElement('button');
|
||||
button.style.display = 'inline-flex';
|
||||
button.style.alignItems = 'center';
|
||||
button.style.opacity = item.hidden ? '.3' : '';
|
||||
button.onclick = () => {
|
||||
c.setDatasetVisibility(item.datasetIndex, !c.isDatasetVisible(item.datasetIndex));
|
||||
c.update();
|
||||
};
|
||||
// Color box
|
||||
const box = document.createElement('span');
|
||||
box.style.display = 'block';
|
||||
box.style.width = tailwindConfig().theme.width[3];
|
||||
box.style.height = tailwindConfig().theme.height[3];
|
||||
box.style.borderRadius = tailwindConfig().theme.borderRadius.full;
|
||||
box.style.marginRight = tailwindConfig().theme.margin[2];
|
||||
box.style.borderWidth = '3px';
|
||||
box.style.borderColor = item.fillStyle;
|
||||
box.style.pointerEvents = 'none';
|
||||
// Label
|
||||
const labelContainer = document.createElement('span');
|
||||
labelContainer.style.display = 'flex';
|
||||
labelContainer.style.alignItems = 'center';
|
||||
const value = document.createElement('span');
|
||||
value.style.color = tailwindConfig().theme.colors.slate[800];
|
||||
value.style.fontSize = tailwindConfig().theme.fontSize['3xl'][0];
|
||||
value.style.lineHeight = tailwindConfig().theme.fontSize['3xl'][1].lineHeight;
|
||||
value.style.fontWeight = tailwindConfig().theme.fontWeight.bold;
|
||||
value.style.marginRight = tailwindConfig().theme.margin[2];
|
||||
value.style.pointerEvents = 'none';
|
||||
const label = document.createElement('span');
|
||||
label.style.color = tailwindConfig().theme.colors.slate[500];
|
||||
label.style.fontSize = tailwindConfig().theme.fontSize.sm[0];
|
||||
label.style.lineHeight = tailwindConfig().theme.fontSize.sm[1].lineHeight;
|
||||
const theValue = c.data.datasets[item.datasetIndex].data.reduce((a, b) => a + b, 0);
|
||||
const valueText = document.createTextNode(formatValue(theValue));
|
||||
const labelText = document.createTextNode(item.text);
|
||||
value.appendChild(valueText);
|
||||
label.appendChild(labelText);
|
||||
li.appendChild(button);
|
||||
button.appendChild(box);
|
||||
button.appendChild(labelContainer);
|
||||
labelContainer.appendChild(value);
|
||||
labelContainer.appendChild(label);
|
||||
ul.appendChild(li);
|
||||
});
|
||||
},
|
||||
}],
|
||||
});
|
||||
return () => chart.destroy();
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<div className="px-5 py-3">
|
||||
<ul ref={legend} className="flex flex-wrap"></ul>
|
||||
</div>
|
||||
<div className="grow">
|
||||
<canvas ref={canvas} width={width} height={height}></canvas>
|
||||
</div>
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
|
||||
export default BarChart01;
|
||||
@@ -1,99 +0,0 @@
|
||||
import React, { useRef, useEffect } from 'react';
|
||||
|
||||
import {
|
||||
Chart, BarController, BarElement, LinearScale, TimeScale, Tooltip, Legend,
|
||||
} from 'chart.js';
|
||||
import 'chartjs-adapter-moment';
|
||||
|
||||
// Import utilities
|
||||
import { formatValue } from '../utils/Utils';
|
||||
|
||||
Chart.register(BarController, BarElement, LinearScale, TimeScale, Tooltip, Legend);
|
||||
|
||||
function BarChart02({
|
||||
data,
|
||||
width,
|
||||
height
|
||||
}) {
|
||||
|
||||
const canvas = useRef(null);
|
||||
|
||||
useEffect(() => {
|
||||
const ctx = canvas.current;
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
const chart = new Chart(ctx, {
|
||||
type: 'bar',
|
||||
data: data,
|
||||
options: {
|
||||
layout: {
|
||||
padding: {
|
||||
top: 12,
|
||||
bottom: 16,
|
||||
left: 20,
|
||||
right: 20,
|
||||
},
|
||||
},
|
||||
scales: {
|
||||
y: {
|
||||
stacked: true,
|
||||
grid: {
|
||||
drawBorder: false,
|
||||
},
|
||||
beginAtZero: true,
|
||||
ticks: {
|
||||
maxTicksLimit: 5,
|
||||
callback: (value) => formatValue(value),
|
||||
},
|
||||
},
|
||||
x: {
|
||||
stacked: true,
|
||||
type: 'time',
|
||||
time: {
|
||||
parser: 'MM-DD-YYYY',
|
||||
unit: 'month',
|
||||
displayFormats: {
|
||||
month: 'MMM YY',
|
||||
},
|
||||
},
|
||||
grid: {
|
||||
display: false,
|
||||
drawBorder: false,
|
||||
},
|
||||
ticks: {
|
||||
autoSkipPadding: 48,
|
||||
maxRotation: 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
plugins: {
|
||||
legend: {
|
||||
display: false,
|
||||
},
|
||||
tooltip: {
|
||||
callbacks: {
|
||||
title: () => false, // Disable tooltip title
|
||||
label: (context) => formatValue(context.parsed.y),
|
||||
},
|
||||
},
|
||||
},
|
||||
interaction: {
|
||||
intersect: false,
|
||||
mode: 'nearest',
|
||||
},
|
||||
animation: {
|
||||
duration: 200,
|
||||
},
|
||||
maintainAspectRatio: false,
|
||||
resizeDelay: 200,
|
||||
},
|
||||
});
|
||||
return () => chart.destroy();
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<canvas ref={canvas} width={width} height={height}></canvas>
|
||||
);
|
||||
}
|
||||
|
||||
export default BarChart02;
|
||||
@@ -1,156 +0,0 @@
|
||||
import React, { useRef, useEffect } from 'react';
|
||||
|
||||
import {
|
||||
Chart, BarController, BarElement, LinearScale, TimeScale, Tooltip, Legend,
|
||||
} from 'chart.js';
|
||||
import 'chartjs-adapter-moment';
|
||||
|
||||
// Import utilities
|
||||
import { tailwindConfig, formatThousands } from '../utils/Utils';
|
||||
|
||||
Chart.register(BarController, BarElement, LinearScale, TimeScale, Tooltip, Legend);
|
||||
|
||||
function BarChart03({
|
||||
data,
|
||||
width,
|
||||
height
|
||||
}) {
|
||||
|
||||
const canvas = useRef(null);
|
||||
const legend = useRef(null);
|
||||
|
||||
useEffect(() => {
|
||||
const ctx = canvas.current;
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
const chart = new Chart(ctx, {
|
||||
type: 'bar',
|
||||
data: data,
|
||||
options: {
|
||||
layout: {
|
||||
padding: {
|
||||
top: 12,
|
||||
bottom: 16,
|
||||
left: 20,
|
||||
right: 20,
|
||||
},
|
||||
},
|
||||
scales: {
|
||||
y: {
|
||||
stacked: true,
|
||||
grid: {
|
||||
drawBorder: false,
|
||||
},
|
||||
beginAtZero: true,
|
||||
ticks: {
|
||||
maxTicksLimit: 5,
|
||||
callback: (value) => formatThousands(value),
|
||||
},
|
||||
},
|
||||
x: {
|
||||
stacked: true,
|
||||
type: 'time',
|
||||
time: {
|
||||
parser: 'MM-DD-YYYY',
|
||||
unit: 'month',
|
||||
displayFormats: {
|
||||
month: 'MMM',
|
||||
},
|
||||
},
|
||||
grid: {
|
||||
display: false,
|
||||
drawBorder: false,
|
||||
},
|
||||
ticks: {
|
||||
autoSkipPadding: 48,
|
||||
maxRotation: 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
plugins: {
|
||||
legend: {
|
||||
display: false,
|
||||
},
|
||||
tooltip: {
|
||||
callbacks: {
|
||||
title: () => false, // Disable tooltip title
|
||||
label: (context) => formatThousands(context.parsed.y),
|
||||
},
|
||||
},
|
||||
},
|
||||
interaction: {
|
||||
intersect: false,
|
||||
mode: 'nearest',
|
||||
},
|
||||
animation: {
|
||||
duration: 500,
|
||||
},
|
||||
maintainAspectRatio: false,
|
||||
resizeDelay: 200,
|
||||
},
|
||||
plugins: [{
|
||||
id: 'htmlLegend',
|
||||
afterUpdate(c, args, options) {
|
||||
const ul = legend.current
|
||||
if (!ul) return
|
||||
// Remove old legend items
|
||||
while (ul.firstChild) {
|
||||
ul.firstChild.remove()
|
||||
}
|
||||
// Reuse the built-in legendItems generator
|
||||
const items = c.options.plugins.legend.labels.generateLabels(c)
|
||||
items.forEach((item) => {
|
||||
const li = document.createElement('li')
|
||||
li.style.marginRight = tailwindConfig().theme.margin[3];
|
||||
// Button element
|
||||
const button = document.createElement('button')
|
||||
button.style.display = 'inline-flex';
|
||||
button.style.alignItems = 'center';
|
||||
button.style.opacity = item.hidden ? '.3' : '';
|
||||
button.onclick = () => {
|
||||
c.setDatasetVisibility(item.datasetIndex, !c.isDatasetVisible(item.datasetIndex))
|
||||
c.update()
|
||||
};
|
||||
// Color box
|
||||
const box = document.createElement('span')
|
||||
box.style.display = 'block';
|
||||
box.style.width = tailwindConfig().theme.width[3];
|
||||
box.style.height = tailwindConfig().theme.height[3];
|
||||
box.style.borderRadius = tailwindConfig().theme.borderRadius.full;
|
||||
box.style.marginRight = tailwindConfig().theme.margin[2];
|
||||
box.style.borderWidth = '3px';
|
||||
box.style.borderColor = item.fillStyle;
|
||||
box.style.pointerEvents = 'none';
|
||||
// Label
|
||||
const label = document.createElement('span')
|
||||
label.style.color = tailwindConfig().theme.colors.slate[500];
|
||||
label.style.fontSize = tailwindConfig().theme.fontSize.sm[0];
|
||||
label.style.lineHeight = tailwindConfig().theme.fontSize.sm[1].lineHeight;
|
||||
const labelText = document.createTextNode(item.text)
|
||||
label.appendChild(labelText)
|
||||
li.appendChild(button)
|
||||
button.appendChild(box)
|
||||
button.appendChild(label)
|
||||
ul.appendChild(li)
|
||||
})
|
||||
},
|
||||
}],
|
||||
});
|
||||
return () => chart.destroy();
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<div className="px-5 py-4">
|
||||
<div className="grow mb-1">
|
||||
<ul ref={legend} className="flex flex-wrap"></ul>
|
||||
</div>
|
||||
</div>
|
||||
<div className="grow">
|
||||
<canvas ref={canvas} width={width} height={height}></canvas>
|
||||
</div>
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
|
||||
export default BarChart03;
|
||||
@@ -1,149 +0,0 @@
|
||||
import React, { useRef, useEffect } from 'react';
|
||||
|
||||
import {
|
||||
Chart, BarController, BarElement, LinearScale, TimeScale, Tooltip, Legend,
|
||||
} from 'chart.js';
|
||||
import 'chartjs-adapter-moment';
|
||||
|
||||
// Import utilities
|
||||
import { tailwindConfig, formatThousands } from '../utils/Utils';
|
||||
|
||||
Chart.register(BarController, BarElement, LinearScale, TimeScale, Tooltip, Legend);
|
||||
|
||||
function BarChart04({
|
||||
data,
|
||||
width,
|
||||
height
|
||||
}) {
|
||||
|
||||
const canvas = useRef(null);
|
||||
const legend = useRef(null);
|
||||
|
||||
useEffect(() => {
|
||||
const ctx = canvas.current;
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
const chart = new Chart(ctx, {
|
||||
type: 'bar',
|
||||
data: data,
|
||||
options: {
|
||||
indexAxis: 'y',
|
||||
layout: {
|
||||
padding: {
|
||||
top: 12,
|
||||
bottom: 16,
|
||||
left: 20,
|
||||
right: 20,
|
||||
},
|
||||
},
|
||||
scales: {
|
||||
y: {
|
||||
type: 'time',
|
||||
time: {
|
||||
parser: 'MM-DD-YYYY',
|
||||
unit: 'month',
|
||||
displayFormats: {
|
||||
month: 'MMM',
|
||||
},
|
||||
},
|
||||
grid: {
|
||||
display: false,
|
||||
drawBorder: false,
|
||||
},
|
||||
},
|
||||
x: {
|
||||
grid: {
|
||||
drawBorder: false,
|
||||
},
|
||||
ticks: {
|
||||
maxTicksLimit: 3,
|
||||
align: 'end',
|
||||
callback: (value) => formatThousands(value),
|
||||
},
|
||||
},
|
||||
},
|
||||
plugins: {
|
||||
legend: {
|
||||
display: false,
|
||||
},
|
||||
tooltip: {
|
||||
callbacks: {
|
||||
title: () => false, // Disable tooltip title
|
||||
label: (context) => formatThousands(context.parsed.x),
|
||||
},
|
||||
},
|
||||
},
|
||||
interaction: {
|
||||
intersect: false,
|
||||
mode: 'nearest',
|
||||
},
|
||||
animation: {
|
||||
duration: 500,
|
||||
},
|
||||
maintainAspectRatio: false,
|
||||
resizeDelay: 200,
|
||||
},
|
||||
plugins: [{
|
||||
id: 'htmlLegend',
|
||||
afterUpdate(c, args, options) {
|
||||
const ul = legend.current
|
||||
if (!ul) return
|
||||
// Remove old legend items
|
||||
while (ul.firstChild) {
|
||||
ul.firstChild.remove()
|
||||
}
|
||||
// Reuse the built-in legendItems generator
|
||||
const items = c.options.plugins.legend.labels.generateLabels(c)
|
||||
items.forEach((item) => {
|
||||
const li = document.createElement('li')
|
||||
li.style.marginRight = tailwindConfig().theme.margin[4]
|
||||
// Button element
|
||||
const button = document.createElement('button')
|
||||
button.style.display = 'inline-flex'
|
||||
button.style.alignItems = 'center'
|
||||
button.style.opacity = item.hidden ? '.3' : ''
|
||||
button.onclick = () => {
|
||||
c.setDatasetVisibility(item.datasetIndex, !c.isDatasetVisible(item.datasetIndex))
|
||||
c.update()
|
||||
}
|
||||
// Color box
|
||||
const box = document.createElement('span')
|
||||
box.style.display = 'block'
|
||||
box.style.width = tailwindConfig().theme.width[3]
|
||||
box.style.height = tailwindConfig().theme.height[3]
|
||||
box.style.borderRadius = tailwindConfig().theme.borderRadius.full
|
||||
box.style.marginRight = tailwindConfig().theme.margin[2]
|
||||
box.style.borderWidth = '3px'
|
||||
box.style.borderColor = item.fillStyle
|
||||
box.style.pointerEvents = 'none'
|
||||
// Label
|
||||
const label = document.createElement('span')
|
||||
label.style.color = tailwindConfig().theme.colors.slate[500]
|
||||
label.style.fontSize = tailwindConfig().theme.fontSize.sm[0]
|
||||
label.style.lineHeight = tailwindConfig().theme.fontSize.sm[1].lineHeight
|
||||
const labelText = document.createTextNode(item.text)
|
||||
label.appendChild(labelText)
|
||||
li.appendChild(button)
|
||||
button.appendChild(box)
|
||||
button.appendChild(label)
|
||||
ul.appendChild(li)
|
||||
})
|
||||
},
|
||||
}],
|
||||
});
|
||||
return () => chart.destroy();
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<div className="px-5 py-4">
|
||||
<ul ref={legend} className="flex flex-wrap"></ul>
|
||||
</div>
|
||||
<div className="grow">
|
||||
<canvas ref={canvas} width={width} height={height}></canvas>
|
||||
</div>
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
|
||||
export default BarChart04;
|
||||
@@ -1,157 +0,0 @@
|
||||
import React, { useRef, useEffect } from 'react';
|
||||
|
||||
import {
|
||||
Chart, BarController, BarElement, LinearScale, TimeScale, Tooltip, Legend,
|
||||
} from 'chart.js';
|
||||
import 'chartjs-adapter-moment';
|
||||
|
||||
// Import utilities
|
||||
import { tailwindConfig, formatValue } from '../utils/Utils';
|
||||
|
||||
Chart.register(BarController, BarElement, LinearScale, TimeScale, Tooltip, Legend);
|
||||
|
||||
function BarChart05({
|
||||
data,
|
||||
width,
|
||||
height
|
||||
}) {
|
||||
|
||||
const canvas = useRef(null);
|
||||
const legend = useRef(null);
|
||||
|
||||
useEffect(() => {
|
||||
const ctx = canvas.current;
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
const chart = new Chart(ctx, {
|
||||
type: 'bar',
|
||||
data: data,
|
||||
options: {
|
||||
layout: {
|
||||
padding: {
|
||||
top: 12,
|
||||
bottom: 16,
|
||||
left: 20,
|
||||
right: 20,
|
||||
},
|
||||
},
|
||||
scales: {
|
||||
y: {
|
||||
grid: {
|
||||
drawBorder: false,
|
||||
},
|
||||
ticks: {
|
||||
maxTicksLimit: 5,
|
||||
callback: (value) => formatValue(value),
|
||||
},
|
||||
},
|
||||
x: {
|
||||
type: 'time',
|
||||
time: {
|
||||
parser: 'MM-DD-YYYY',
|
||||
unit: 'month',
|
||||
displayFormats: {
|
||||
month: 'MMM YY',
|
||||
},
|
||||
},
|
||||
grid: {
|
||||
display: false,
|
||||
drawBorder: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
plugins: {
|
||||
legend: {
|
||||
display: false,
|
||||
},
|
||||
tooltip: {
|
||||
callbacks: {
|
||||
title: () => false, // Disable tooltip title
|
||||
label: (context) => formatValue(context.parsed.y),
|
||||
},
|
||||
},
|
||||
},
|
||||
interaction: {
|
||||
intersect: false,
|
||||
mode: 'nearest',
|
||||
},
|
||||
animation: {
|
||||
duration: 500,
|
||||
},
|
||||
maintainAspectRatio: false,
|
||||
resizeDelay: 200,
|
||||
},
|
||||
plugins: [
|
||||
{
|
||||
id: 'htmlLegend',
|
||||
afterUpdate(c, args, options) {
|
||||
const ul = legend.current;
|
||||
if (!ul) return;
|
||||
// Remove old legend items
|
||||
while (ul.firstChild) {
|
||||
ul.firstChild.remove();
|
||||
}
|
||||
// Reuse the built-in legendItems generator
|
||||
const items = c.options.plugins.legend.labels.generateLabels(c);
|
||||
items.forEach((item) => {
|
||||
const li = document.createElement('li');
|
||||
li.style.marginRight = tailwindConfig().theme.margin[4];
|
||||
// Button element
|
||||
const button = document.createElement('button');
|
||||
button.style.display = 'inline-flex';
|
||||
button.style.alignItems = 'center';
|
||||
button.style.opacity = item.hidden ? '.3' : '';
|
||||
button.onclick = () => {
|
||||
c.setDatasetVisibility(item.datasetIndex, !c.isDatasetVisible(item.datasetIndex));
|
||||
c.update();
|
||||
};
|
||||
// Color box
|
||||
const box = document.createElement('span');
|
||||
box.style.display = 'block';
|
||||
box.style.width = tailwindConfig().theme.width[3];
|
||||
box.style.height = tailwindConfig().theme.height[3];
|
||||
box.style.borderRadius = tailwindConfig().theme.borderRadius.full;
|
||||
box.style.marginRight = tailwindConfig().theme.margin[2];
|
||||
box.style.borderWidth = '3px';
|
||||
box.style.borderColor = item.fillStyle;
|
||||
box.style.pointerEvents = 'none';
|
||||
// Label
|
||||
const label = document.createElement('span');
|
||||
label.style.color = tailwindConfig().theme.colors.slate[500];
|
||||
label.style.fontSize = tailwindConfig().theme.fontSize.sm[0];
|
||||
label.style.lineHeight = tailwindConfig().theme.fontSize.sm[1].lineHeight;
|
||||
const labelText = document.createTextNode(item.text);
|
||||
label.appendChild(labelText);
|
||||
li.appendChild(button);
|
||||
button.appendChild(box);
|
||||
button.appendChild(label);
|
||||
ul.appendChild(li);
|
||||
});
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
return () => chart.destroy();
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<div className="px-5 py-3">
|
||||
<div className="flex flex-wrap justify-between items-center">
|
||||
<div className="flex items-center">
|
||||
<div className="text-3xl font-bold text-slate-800 mr-2">$1,347.09</div>
|
||||
<div className="text-sm">Net</div>
|
||||
</div>
|
||||
<div className="grow ml-2">
|
||||
<ul ref={legend} className="flex flex-wrap justify-end"></ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="grow">
|
||||
<canvas ref={canvas} width={width} height={height}></canvas>
|
||||
</div>
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
|
||||
export default BarChart05;
|
||||
@@ -1,164 +0,0 @@
|
||||
import React, { useRef, useEffect } from 'react';
|
||||
|
||||
import {
|
||||
Chart, BarController, BarElement, LinearScale, CategoryScale, Tooltip, Legend,
|
||||
} from 'chart.js';
|
||||
import 'chartjs-adapter-moment';
|
||||
|
||||
// Import utilities
|
||||
import { tailwindConfig, formatValue } from '../utils/Utils';
|
||||
|
||||
// Import images
|
||||
import revolutIcon from '../images/company-icon-01.svg';
|
||||
import hsbcIcon from '../images/company-icon-02.svg';
|
||||
import qontoIcon from '../images/company-icon-03.svg';
|
||||
import n26Icon from '../images/company-icon-04.svg';
|
||||
|
||||
Chart.register(BarController, BarElement, LinearScale, CategoryScale, Tooltip, Legend);
|
||||
const images = [revolutIcon, hsbcIcon, qontoIcon, n26Icon];
|
||||
|
||||
function BarChart06({
|
||||
data,
|
||||
width,
|
||||
height
|
||||
}) {
|
||||
|
||||
const canvas = useRef(null);
|
||||
const legend = useRef(null);
|
||||
|
||||
useEffect(() => {
|
||||
const ctx = canvas.current;
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
const chart = new Chart(ctx, {
|
||||
type: 'bar',
|
||||
data: data,
|
||||
options: {
|
||||
indexAxis: 'y',
|
||||
layout: {
|
||||
padding: {
|
||||
top: 12,
|
||||
bottom: 16,
|
||||
left: 72,
|
||||
right: 20,
|
||||
},
|
||||
},
|
||||
scales: {
|
||||
y: {
|
||||
grid: {
|
||||
display: false,
|
||||
drawBorder: false,
|
||||
drawTicks: false,
|
||||
},
|
||||
ticks: {
|
||||
display: false,
|
||||
},
|
||||
},
|
||||
x: {
|
||||
grid: {
|
||||
drawBorder: false,
|
||||
},
|
||||
ticks: {
|
||||
maxTicksLimit: 3,
|
||||
align: 'end',
|
||||
callback: (value) => formatValue(value),
|
||||
},
|
||||
},
|
||||
},
|
||||
plugins: {
|
||||
legend: {
|
||||
display: false,
|
||||
},
|
||||
tooltip: {
|
||||
callbacks: {
|
||||
title: () => false, // Disable tooltip title
|
||||
label: (context) => formatValue(context.parsed.x),
|
||||
},
|
||||
},
|
||||
},
|
||||
interaction: {
|
||||
intersect: false,
|
||||
mode: 'nearest',
|
||||
},
|
||||
animation: {
|
||||
duration: 500,
|
||||
},
|
||||
maintainAspectRatio: false,
|
||||
resizeDelay: 200,
|
||||
},
|
||||
plugins: [
|
||||
{
|
||||
id: 'htmlLegend',
|
||||
afterUpdate(c, args, options) {
|
||||
const ul = legend.current;
|
||||
if (!ul) return;
|
||||
// Remove old legend items
|
||||
while (ul.firstChild) {
|
||||
ul.firstChild.remove();
|
||||
}
|
||||
// Reuse the built-in legendItems generator
|
||||
const items = c.options.plugins.legend.labels.generateLabels(c);
|
||||
items.forEach((item) => {
|
||||
const li = document.createElement('li');
|
||||
li.style.marginRight = tailwindConfig().theme.margin[4];
|
||||
// Button element
|
||||
const button = document.createElement('button');
|
||||
button.style.display = 'inline-flex';
|
||||
button.style.alignItems = 'center';
|
||||
button.style.opacity = item.hidden ? '.3' : '';
|
||||
button.onclick = () => {
|
||||
c.setDatasetVisibility(item.datasetIndex, !c.isDatasetVisible(item.datasetIndex));
|
||||
c.update();
|
||||
};
|
||||
// Color box
|
||||
const box = document.createElement('span');
|
||||
box.style.display = 'block';
|
||||
box.style.width = tailwindConfig().theme.width[3];
|
||||
box.style.height = tailwindConfig().theme.height[3];
|
||||
box.style.borderRadius = tailwindConfig().theme.borderRadius.full;
|
||||
box.style.marginRight = tailwindConfig().theme.margin[2];
|
||||
box.style.borderWidth = '3px';
|
||||
box.style.borderColor = item.fillStyle;
|
||||
box.style.pointerEvents = 'none';
|
||||
// Label
|
||||
const label = document.createElement('span');
|
||||
label.style.color = tailwindConfig().theme.colors.slate[500];
|
||||
label.style.fontSize = tailwindConfig().theme.fontSize.sm[0];
|
||||
label.style.lineHeight = tailwindConfig().theme.fontSize.sm[1].lineHeight;
|
||||
const labelText = document.createTextNode(item.text);
|
||||
label.appendChild(labelText);
|
||||
li.appendChild(button);
|
||||
button.appendChild(box);
|
||||
button.appendChild(label);
|
||||
ul.appendChild(li);
|
||||
});
|
||||
},
|
||||
afterDraw(c) {
|
||||
const xAxis = c.scales.x;
|
||||
const yAxis = c.scales.y;
|
||||
yAxis.ticks.forEach((value, index) => {
|
||||
const y = yAxis.getPixelForTick(index);
|
||||
const image = new Image();
|
||||
image.src = images[index];
|
||||
c.ctx.drawImage(image, xAxis.left - 52, y - 18);
|
||||
});
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
return () => chart.destroy();
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<div className="px-5 py-4">
|
||||
<ul ref={legend} className="flex flex-wrap"></ul>
|
||||
</div>
|
||||
<div className="grow">
|
||||
<canvas ref={canvas} width={width} height={height}></canvas>
|
||||
</div>
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
|
||||
export default BarChart06;
|
||||
@@ -1,42 +0,0 @@
|
||||
// Import Chart.js
|
||||
import { Chart, Tooltip } from 'chart.js';
|
||||
// Import Tailwind config
|
||||
import { tailwindConfig } from '../utils/Utils';
|
||||
|
||||
Chart.register(Tooltip);
|
||||
|
||||
// Define Chart.js default settings
|
||||
Chart.defaults.font.family = '"Inter", sans-serif';
|
||||
Chart.defaults.font.weight = '500';
|
||||
Chart.defaults.color = tailwindConfig().theme.colors.slate[400];
|
||||
Chart.defaults.scale.grid.color = tailwindConfig().theme.colors.slate[100];
|
||||
Chart.defaults.plugins.tooltip.titleColor = tailwindConfig().theme.colors.slate[800];
|
||||
Chart.defaults.plugins.tooltip.bodyColor = tailwindConfig().theme.colors.slate[800];
|
||||
Chart.defaults.plugins.tooltip.backgroundColor = tailwindConfig().theme.colors.white;
|
||||
Chart.defaults.plugins.tooltip.borderWidth = 1;
|
||||
Chart.defaults.plugins.tooltip.borderColor = tailwindConfig().theme.colors.slate[200];
|
||||
Chart.defaults.plugins.tooltip.displayColors = false;
|
||||
Chart.defaults.plugins.tooltip.mode = 'nearest';
|
||||
Chart.defaults.plugins.tooltip.intersect = false;
|
||||
Chart.defaults.plugins.tooltip.position = 'nearest';
|
||||
Chart.defaults.plugins.tooltip.caretSize = 0;
|
||||
Chart.defaults.plugins.tooltip.caretPadding = 20;
|
||||
Chart.defaults.plugins.tooltip.cornerRadius = 4;
|
||||
Chart.defaults.plugins.tooltip.padding = 8;
|
||||
|
||||
// Register Chart.js plugin to add a bg option for chart area
|
||||
Chart.register({
|
||||
id: 'chartAreaPlugin',
|
||||
// eslint-disable-next-line object-shorthand
|
||||
beforeDraw: (chart) => {
|
||||
if (chart.config.options.chartArea && chart.config.options.chartArea.backgroundColor) {
|
||||
const ctx = chart.canvas.getContext('2d');
|
||||
const { chartArea } = chart;
|
||||
ctx.save();
|
||||
ctx.fillStyle = chart.config.options.chartArea.backgroundColor;
|
||||
// eslint-disable-next-line max-len
|
||||
ctx.fillRect(chartArea.left, chartArea.top, chartArea.right - chartArea.left, chartArea.bottom - chartArea.top);
|
||||
ctx.restore();
|
||||
}
|
||||
},
|
||||
});
|
||||
@@ -1,114 +0,0 @@
|
||||
import React, { useRef, useEffect } from 'react';
|
||||
|
||||
import {
|
||||
Chart, DoughnutController, ArcElement, TimeScale, Tooltip,
|
||||
} from 'chart.js';
|
||||
import 'chartjs-adapter-moment';
|
||||
|
||||
// Import utilities
|
||||
import { tailwindConfig } from '../utils/Utils';
|
||||
|
||||
Chart.register(DoughnutController, ArcElement, TimeScale, Tooltip);
|
||||
|
||||
function DoughnutChart({
|
||||
data,
|
||||
width,
|
||||
height
|
||||
}) {
|
||||
|
||||
const canvas = useRef(null);
|
||||
const legend = useRef(null);
|
||||
|
||||
useEffect(() => {
|
||||
const ctx = canvas.current;
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
const chart = new Chart(ctx, {
|
||||
type: 'doughnut',
|
||||
data: data,
|
||||
options: {
|
||||
cutout: '80%',
|
||||
layout: {
|
||||
padding: 24,
|
||||
},
|
||||
plugins: {
|
||||
legend: {
|
||||
display: false,
|
||||
},
|
||||
},
|
||||
interaction: {
|
||||
intersect: false,
|
||||
mode: 'nearest',
|
||||
},
|
||||
animation: {
|
||||
duration: 500,
|
||||
},
|
||||
maintainAspectRatio: false,
|
||||
resizeDelay: 200,
|
||||
},
|
||||
plugins: [{
|
||||
id: 'htmlLegend',
|
||||
afterUpdate(c, args, options) {
|
||||
const ul = legend.current;
|
||||
if (!ul) return;
|
||||
// Remove old legend items
|
||||
while (ul.firstChild) {
|
||||
ul.firstChild.remove();
|
||||
}
|
||||
// Reuse the built-in legendItems generator
|
||||
const items = c.options.plugins.legend.labels.generateLabels(c);
|
||||
items.forEach((item) => {
|
||||
const li = document.createElement('li');
|
||||
li.style.margin = tailwindConfig().theme.margin[1];
|
||||
// Button element
|
||||
const button = document.createElement('button');
|
||||
button.classList.add('btn-xs');
|
||||
button.style.backgroundColor = tailwindConfig().theme.colors.white;
|
||||
button.style.borderWidth = tailwindConfig().theme.borderWidth[1];
|
||||
button.style.borderColor = tailwindConfig().theme.colors.slate[200];
|
||||
button.style.color = tailwindConfig().theme.colors.slate[500];
|
||||
button.style.boxShadow = tailwindConfig().theme.boxShadow.md;
|
||||
button.style.opacity = item.hidden ? '.3' : '';
|
||||
button.onclick = () => {
|
||||
c.toggleDataVisibility(item.index, !item.index);
|
||||
c.update();
|
||||
};
|
||||
// Color box
|
||||
const box = document.createElement('span');
|
||||
box.style.display = 'block';
|
||||
box.style.width = tailwindConfig().theme.width[2];
|
||||
box.style.height = tailwindConfig().theme.height[2];
|
||||
box.style.backgroundColor = item.fillStyle;
|
||||
box.style.borderRadius = tailwindConfig().theme.borderRadius.sm;
|
||||
box.style.marginRight = tailwindConfig().theme.margin[1];
|
||||
box.style.pointerEvents = 'none';
|
||||
// Label
|
||||
const label = document.createElement('span');
|
||||
label.style.display = 'flex';
|
||||
label.style.alignItems = 'center';
|
||||
const labelText = document.createTextNode(item.text);
|
||||
label.appendChild(labelText);
|
||||
li.appendChild(button);
|
||||
button.appendChild(box);
|
||||
button.appendChild(label);
|
||||
ul.appendChild(li);
|
||||
});
|
||||
},
|
||||
}],
|
||||
});
|
||||
return () => chart.destroy();
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="grow flex flex-col justify-center">
|
||||
<div>
|
||||
<canvas ref={canvas} width={width} height={height}></canvas>
|
||||
</div>
|
||||
<div className="px-5 pt-2 pb-6">
|
||||
<ul ref={legend} className="flex flex-wrap justify-center -m-1"></ul>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default DoughnutChart;
|
||||
@@ -1,76 +0,0 @@
|
||||
import React, { useRef, useEffect } from 'react';
|
||||
|
||||
import {
|
||||
Chart, LineController, LineElement, Filler, PointElement, LinearScale, TimeScale, Tooltip,
|
||||
} from 'chart.js';
|
||||
import 'chartjs-adapter-moment';
|
||||
|
||||
// Import utilities
|
||||
import { tailwindConfig, formatValue } from '../utils/Utils';
|
||||
|
||||
Chart.register(LineController, LineElement, Filler, PointElement, LinearScale, TimeScale, Tooltip);
|
||||
|
||||
function LineChart01({
|
||||
data,
|
||||
width,
|
||||
height
|
||||
}) {
|
||||
|
||||
const canvas = useRef(null);
|
||||
|
||||
useEffect(() => {
|
||||
const ctx = canvas.current;
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
const chart = new Chart(ctx, {
|
||||
type: 'line',
|
||||
data: data,
|
||||
options: {
|
||||
chartArea: {
|
||||
backgroundColor: tailwindConfig().theme.colors.slate[50],
|
||||
},
|
||||
layout: {
|
||||
padding: 20,
|
||||
},
|
||||
scales: {
|
||||
y: {
|
||||
display: false,
|
||||
beginAtZero: true,
|
||||
},
|
||||
x: {
|
||||
type: 'time',
|
||||
time: {
|
||||
parser: 'MM-DD-YYYY',
|
||||
unit: 'month',
|
||||
},
|
||||
display: false,
|
||||
},
|
||||
},
|
||||
plugins: {
|
||||
tooltip: {
|
||||
callbacks: {
|
||||
title: () => false, // Disable tooltip title
|
||||
label: (context) => formatValue(context.parsed.y),
|
||||
},
|
||||
},
|
||||
legend: {
|
||||
display: false,
|
||||
},
|
||||
},
|
||||
interaction: {
|
||||
intersect: false,
|
||||
mode: 'nearest',
|
||||
},
|
||||
maintainAspectRatio: false,
|
||||
resizeDelay: 200,
|
||||
},
|
||||
});
|
||||
return () => chart.destroy();
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<canvas ref={canvas} width={width} height={height}></canvas>
|
||||
);
|
||||
}
|
||||
|
||||
export default LineChart01;
|
||||
@@ -1,153 +0,0 @@
|
||||
import React, { useRef, useEffect } from 'react';
|
||||
|
||||
import {
|
||||
Chart, LineController, LineElement, Filler, PointElement, LinearScale, TimeScale, Tooltip,
|
||||
} from 'chart.js';
|
||||
import 'chartjs-adapter-moment';
|
||||
|
||||
// Import utilities
|
||||
import { tailwindConfig, formatValue } from '../utils/Utils';
|
||||
|
||||
Chart.register(LineController, LineElement, Filler, PointElement, LinearScale, TimeScale, Tooltip);
|
||||
|
||||
function LineChart02({
|
||||
data,
|
||||
width,
|
||||
height
|
||||
}) {
|
||||
|
||||
const canvas = useRef(null);
|
||||
const legend = useRef(null);
|
||||
|
||||
useEffect(() => {
|
||||
const ctx = canvas.current;
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
const chart = new Chart(ctx, {
|
||||
type: 'line',
|
||||
data: data,
|
||||
options: {
|
||||
layout: {
|
||||
padding: 20,
|
||||
},
|
||||
scales: {
|
||||
y: {
|
||||
grid: {
|
||||
drawBorder: false,
|
||||
beginAtZero: true,
|
||||
},
|
||||
ticks: {
|
||||
maxTicksLimit: 5,
|
||||
callback: (value) => formatValue(value),
|
||||
},
|
||||
},
|
||||
x: {
|
||||
type: 'time',
|
||||
time: {
|
||||
parser: 'MM-DD-YYYY',
|
||||
unit: 'month',
|
||||
displayFormats: {
|
||||
month: 'MMM YY',
|
||||
},
|
||||
},
|
||||
grid: {
|
||||
display: false,
|
||||
drawBorder: false,
|
||||
},
|
||||
ticks: {
|
||||
autoSkipPadding: 48,
|
||||
maxRotation: 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
plugins: {
|
||||
legend: {
|
||||
display: false,
|
||||
},
|
||||
tooltip: {
|
||||
callbacks: {
|
||||
title: () => false, // Disable tooltip title
|
||||
label: (context) => formatValue(context.parsed.y),
|
||||
},
|
||||
},
|
||||
},
|
||||
interaction: {
|
||||
intersect: false,
|
||||
mode: 'nearest',
|
||||
},
|
||||
maintainAspectRatio: false,
|
||||
resizeDelay: 200,
|
||||
},
|
||||
plugins: [{
|
||||
id: 'htmlLegend',
|
||||
afterUpdate(c, args, options) {
|
||||
const ul = legend.current;
|
||||
if (!ul) return;
|
||||
// Remove old legend items
|
||||
while (ul.firstChild) {
|
||||
ul.firstChild.remove();
|
||||
}
|
||||
// Reuse the built-in legendItems generator
|
||||
const items = c.options.plugins.legend.labels.generateLabels(c);
|
||||
items.slice(0, 2).forEach((item) => {
|
||||
const li = document.createElement('li');
|
||||
li.style.marginLeft = tailwindConfig().theme.margin[3];
|
||||
// Button element
|
||||
const button = document.createElement('button');
|
||||
button.style.display = 'inline-flex';
|
||||
button.style.alignItems = 'center';
|
||||
button.style.opacity = item.hidden ? '.3' : '';
|
||||
button.onclick = () => {
|
||||
c.setDatasetVisibility(item.datasetIndex, !c.isDatasetVisible(item.datasetIndex));
|
||||
c.update();
|
||||
};
|
||||
// Color box
|
||||
const box = document.createElement('span');
|
||||
box.style.display = 'block';
|
||||
box.style.width = tailwindConfig().theme.width[3];
|
||||
box.style.height = tailwindConfig().theme.height[3];
|
||||
box.style.borderRadius = tailwindConfig().theme.borderRadius.full;
|
||||
box.style.marginRight = tailwindConfig().theme.margin[2];
|
||||
box.style.borderWidth = '3px';
|
||||
box.style.borderColor = c.data.datasets[item.datasetIndex].borderColor;
|
||||
box.style.pointerEvents = 'none';
|
||||
// Label
|
||||
const label = document.createElement('span');
|
||||
label.style.color = tailwindConfig().theme.colors.slate[500];
|
||||
label.style.fontSize = tailwindConfig().theme.fontSize.sm[0];
|
||||
label.style.lineHeight = tailwindConfig().theme.fontSize.sm[1].lineHeight;
|
||||
const labelText = document.createTextNode(item.text);
|
||||
label.appendChild(labelText);
|
||||
li.appendChild(button);
|
||||
button.appendChild(box);
|
||||
button.appendChild(label);
|
||||
ul.appendChild(li);
|
||||
});
|
||||
},
|
||||
}],
|
||||
});
|
||||
return () => chart.destroy();
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<div className="px-5 py-3">
|
||||
<div className="flex flex-wrap justify-between items-end">
|
||||
<div className="flex items-start">
|
||||
<div className="text-3xl font-bold text-slate-800 mr-2">$1,482</div>
|
||||
<div className="text-sm font-semibold text-white px-1.5 bg-amber-500 rounded-full">-22%</div>
|
||||
</div>
|
||||
<div className="grow ml-2 mb-1">
|
||||
<ul ref={legend} className="flex flex-wrap justify-end"></ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/* Chart built with Chart.js 3 */}
|
||||
<div className="grow">
|
||||
<canvas ref={canvas} width={width} height={height}></canvas>
|
||||
</div>
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
|
||||
export default LineChart02;
|
||||
@@ -1,88 +0,0 @@
|
||||
import React, { useRef, useEffect } from 'react';
|
||||
|
||||
import {
|
||||
Chart, LineController, LineElement, Filler, PointElement, LinearScale, TimeScale, Tooltip,
|
||||
} from 'chart.js';
|
||||
import 'chartjs-adapter-moment';
|
||||
|
||||
// Import utilities
|
||||
import { formatThousands } from '../utils/Utils';
|
||||
|
||||
Chart.register(LineController, LineElement, Filler, PointElement, LinearScale, TimeScale, Tooltip);
|
||||
|
||||
function LineChart03({
|
||||
data,
|
||||
width,
|
||||
height
|
||||
}) {
|
||||
|
||||
const canvas = useRef(null);
|
||||
|
||||
useEffect(() => {
|
||||
const ctx = canvas.current;
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
const chart = new Chart(ctx, {
|
||||
type: 'line',
|
||||
data: data,
|
||||
options: {
|
||||
layout: {
|
||||
padding: 20,
|
||||
},
|
||||
scales: {
|
||||
y: {
|
||||
beginAtZero: true,
|
||||
grid: {
|
||||
drawBorder: false,
|
||||
},
|
||||
ticks: {
|
||||
callback: (value) => formatThousands(value),
|
||||
},
|
||||
},
|
||||
x: {
|
||||
type: 'time',
|
||||
time: {
|
||||
parser: 'MM-DD-YYYY',
|
||||
unit: 'month',
|
||||
displayFormats: {
|
||||
month: 'MMM YY',
|
||||
},
|
||||
},
|
||||
grid: {
|
||||
display: false,
|
||||
drawBorder: false,
|
||||
},
|
||||
ticks: {
|
||||
autoSkipPadding: 48,
|
||||
maxRotation: 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
plugins: {
|
||||
legend: {
|
||||
display: false,
|
||||
},
|
||||
tooltip: {
|
||||
callbacks: {
|
||||
title: () => false, // Disable tooltip title
|
||||
label: (context) => formatThousands(context.parsed.y),
|
||||
},
|
||||
},
|
||||
},
|
||||
interaction: {
|
||||
intersect: false,
|
||||
mode: 'nearest',
|
||||
},
|
||||
maintainAspectRatio: false,
|
||||
resizeDelay: 200,
|
||||
},
|
||||
});
|
||||
return () => chart.destroy();
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<canvas ref={canvas} width={width} height={height}></canvas>
|
||||
);
|
||||
}
|
||||
|
||||
export default LineChart03;
|
||||
@@ -1,78 +0,0 @@
|
||||
import React, { useRef, useEffect } from 'react';
|
||||
|
||||
import {
|
||||
Chart, LineController, LineElement, Filler, PointElement, LinearScale, TimeScale, Tooltip,
|
||||
} from 'chart.js';
|
||||
import 'chartjs-adapter-moment';
|
||||
|
||||
// Import utilities
|
||||
import { tailwindConfig, formatThousands } from '../utils/Utils';
|
||||
|
||||
Chart.register(LineController, LineElement, Filler, PointElement, LinearScale, TimeScale, Tooltip);
|
||||
|
||||
function LineChart04({
|
||||
data,
|
||||
width,
|
||||
height
|
||||
}) {
|
||||
|
||||
const canvas = useRef(null);
|
||||
|
||||
useEffect(() => {
|
||||
const ctx = canvas.current;
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
const chart = new Chart(ctx, {
|
||||
type: 'line',
|
||||
data: data,
|
||||
options: {
|
||||
chartArea: {
|
||||
backgroundColor: tailwindConfig().theme.colors.slate[50],
|
||||
},
|
||||
layout: {
|
||||
padding: {
|
||||
left: 20,
|
||||
right: 20,
|
||||
},
|
||||
},
|
||||
scales: {
|
||||
y: {
|
||||
display: false,
|
||||
beginAtZero: true,
|
||||
},
|
||||
x: {
|
||||
type: 'time',
|
||||
time: {
|
||||
parser: 'MM-DD-YYYY',
|
||||
unit: 'month',
|
||||
},
|
||||
display: false,
|
||||
},
|
||||
},
|
||||
plugins: {
|
||||
tooltip: {
|
||||
callbacks: {
|
||||
title: () => false, // Disable tooltip title
|
||||
label: (context) => formatThousands(context.parsed.y),
|
||||
},
|
||||
},
|
||||
legend: {
|
||||
display: false,
|
||||
},
|
||||
},
|
||||
interaction: {
|
||||
intersect: false,
|
||||
mode: 'nearest',
|
||||
},
|
||||
maintainAspectRatio: false,
|
||||
},
|
||||
});
|
||||
return () => chart.destroy();
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<canvas ref={canvas} width={width} height={height}></canvas>
|
||||
);
|
||||
}
|
||||
|
||||
export default LineChart04;
|
||||
@@ -1,157 +0,0 @@
|
||||
import React, { useRef, useEffect } from 'react';
|
||||
|
||||
import {
|
||||
Chart, LineController, LineElement, Filler, PointElement, LinearScale, TimeScale, Tooltip,
|
||||
} from 'chart.js';
|
||||
import 'chartjs-adapter-moment';
|
||||
|
||||
// Import utilities
|
||||
import { tailwindConfig } from '../utils/Utils';
|
||||
|
||||
Chart.register(LineController, LineElement, Filler, PointElement, LinearScale, TimeScale, Tooltip);
|
||||
|
||||
function LineChart05({
|
||||
data,
|
||||
width,
|
||||
height
|
||||
}) {
|
||||
|
||||
const canvas = useRef(null);
|
||||
const legend = useRef(null);
|
||||
|
||||
useEffect(() => {
|
||||
const ctx = canvas.current;
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
const chart = new Chart(ctx, {
|
||||
type: 'line',
|
||||
data: data,
|
||||
options: {
|
||||
layout: {
|
||||
padding: 20,
|
||||
},
|
||||
scales: {
|
||||
y: {
|
||||
beginAtZero: true,
|
||||
grid: {
|
||||
drawBorder: false,
|
||||
},
|
||||
ticks: {
|
||||
maxTicksLimit: 7,
|
||||
callback: (value) => `${value}%`,
|
||||
},
|
||||
},
|
||||
x: {
|
||||
type: 'time',
|
||||
time: {
|
||||
parser: 'MM-DD-YYYY',
|
||||
unit: 'month',
|
||||
displayFormats: {
|
||||
month: 'MMM YY',
|
||||
},
|
||||
},
|
||||
grid: {
|
||||
display: false,
|
||||
drawBorder: false,
|
||||
},
|
||||
ticks: {
|
||||
autoSkipPadding: 48,
|
||||
maxRotation: 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
plugins: {
|
||||
legend: {
|
||||
display: false,
|
||||
},
|
||||
tooltip: {
|
||||
callbacks: {
|
||||
title: () => false, // Disable tooltip title
|
||||
label: (context) => `${context.parsed.y}%`,
|
||||
},
|
||||
},
|
||||
},
|
||||
interaction: {
|
||||
intersect: false,
|
||||
mode: 'nearest',
|
||||
},
|
||||
maintainAspectRatio: false,
|
||||
resizeDelay: 200,
|
||||
},
|
||||
plugins: [
|
||||
{
|
||||
id: 'htmlLegend',
|
||||
afterUpdate(c, args, options) {
|
||||
const ul = legend.current;
|
||||
if (!ul) return;
|
||||
// Remove old legend items
|
||||
while (ul.firstChild) {
|
||||
ul.firstChild.remove();
|
||||
}
|
||||
// Reuse the built-in legendItems generator
|
||||
const items = c.options.plugins.legend.labels.generateLabels(c);
|
||||
items.forEach((item) => {
|
||||
const li = document.createElement('li');
|
||||
li.style.marginLeft = tailwindConfig().theme.margin[3];
|
||||
// Button element
|
||||
const button = document.createElement('button');
|
||||
button.style.display = 'inline-flex';
|
||||
button.style.alignItems = 'center';
|
||||
button.style.opacity = item.hidden ? '.3' : '';
|
||||
button.onclick = () => {
|
||||
c.setDatasetVisibility(item.datasetIndex, !c.isDatasetVisible(item.datasetIndex));
|
||||
c.update();
|
||||
};
|
||||
// Color box
|
||||
const box = document.createElement('span');
|
||||
box.style.display = 'block';
|
||||
box.style.width = tailwindConfig().theme.width[3];
|
||||
box.style.height = tailwindConfig().theme.height[3];
|
||||
box.style.borderRadius = tailwindConfig().theme.borderRadius.full;
|
||||
box.style.marginRight = tailwindConfig().theme.margin[2];
|
||||
box.style.borderWidth = '3px';
|
||||
box.style.borderColor = c.data.datasets[item.datasetIndex].borderColor;
|
||||
box.style.pointerEvents = 'none';
|
||||
// Label
|
||||
const label = document.createElement('span');
|
||||
label.style.color = tailwindConfig().theme.colors.slate[500];
|
||||
label.style.fontSize = tailwindConfig().theme.fontSize.sm[0];
|
||||
label.style.lineHeight = tailwindConfig().theme.fontSize.sm[1].lineHeight;
|
||||
const labelText = document.createTextNode(item.text);
|
||||
label.appendChild(labelText);
|
||||
li.appendChild(button);
|
||||
button.appendChild(box);
|
||||
button.appendChild(label);
|
||||
ul.appendChild(li);
|
||||
});
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
return () => chart.destroy();
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<div className="px-5 py-3">
|
||||
<div className="flex flex-wrap justify-between items-end">
|
||||
<div className="flex items-center">
|
||||
<div className="text-3xl font-bold text-slate-800 mr-2">244.7%</div>
|
||||
<div className="text-sm">
|
||||
<span className="font-medium text-slate-800">17.4%</span> AVG
|
||||
</div>
|
||||
</div>
|
||||
<div className="grow ml-2 mb-1">
|
||||
<ul ref={legend} className="flex flex-wrap justify-end" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/* Chart built with Chart.js 3 */}
|
||||
<div className="grow">
|
||||
<canvas ref={canvas} width={width} height={height}></canvas>
|
||||
</div>
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
|
||||
export default LineChart05;
|
||||
@@ -1,94 +0,0 @@
|
||||
import React, { useRef, useEffect } from 'react';
|
||||
|
||||
import {
|
||||
Chart, LineController, LineElement, Filler, PointElement, LinearScale, TimeScale, Tooltip,
|
||||
} from 'chart.js';
|
||||
import 'chartjs-adapter-moment';
|
||||
|
||||
// Import utilities
|
||||
import { formatValue } from '../utils/Utils';
|
||||
|
||||
Chart.register(LineController, LineElement, Filler, PointElement, LinearScale, TimeScale, Tooltip);
|
||||
|
||||
function LineChart06({
|
||||
data,
|
||||
width,
|
||||
height
|
||||
}) {
|
||||
|
||||
const canvas = useRef(null);
|
||||
|
||||
useEffect(() => {
|
||||
const ctx = canvas.current;
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
const chart = new Chart(ctx, {
|
||||
type: 'line',
|
||||
data: data,
|
||||
options: {
|
||||
layout: {
|
||||
padding: {
|
||||
top: 12,
|
||||
bottom: 16,
|
||||
left: 20,
|
||||
right: 20,
|
||||
},
|
||||
},
|
||||
scales: {
|
||||
y: {
|
||||
beginAtZero: true,
|
||||
grid: {
|
||||
drawBorder: false,
|
||||
},
|
||||
ticks: {
|
||||
maxTicksLimit: 7,
|
||||
callback: (value) => formatValue(value),
|
||||
},
|
||||
},
|
||||
x: {
|
||||
type: 'time',
|
||||
time: {
|
||||
parser: 'MM-DD-YYYY',
|
||||
unit: 'month',
|
||||
displayFormats: {
|
||||
month: 'MMM YY',
|
||||
},
|
||||
},
|
||||
grid: {
|
||||
display: false,
|
||||
drawBorder: false,
|
||||
},
|
||||
ticks: {
|
||||
autoSkipPadding: 48,
|
||||
maxRotation: 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
plugins: {
|
||||
tooltip: {
|
||||
callbacks: {
|
||||
title: () => false, // Disable tooltip title
|
||||
label: (context) => formatValue(context.parsed.y),
|
||||
},
|
||||
},
|
||||
legend: {
|
||||
display: false,
|
||||
},
|
||||
},
|
||||
interaction: {
|
||||
intersect: false,
|
||||
mode: 'nearest',
|
||||
},
|
||||
maintainAspectRatio: false,
|
||||
resizeDelay: 200,
|
||||
},
|
||||
});
|
||||
return () => chart.destroy();
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<canvas ref={canvas} width={width} height={height}></canvas>
|
||||
);
|
||||
}
|
||||
|
||||
export default LineChart06;
|
||||
@@ -1,86 +0,0 @@
|
||||
import React, { useRef, useEffect } from 'react';
|
||||
|
||||
import {
|
||||
Chart, LineController, LineElement, Filler, PointElement, LinearScale, CategoryScale, Tooltip,
|
||||
} from 'chart.js';
|
||||
import 'chartjs-adapter-moment';
|
||||
|
||||
// Import utilities
|
||||
import { formatValue } from '../utils/Utils';
|
||||
|
||||
Chart.register(LineController, LineElement, Filler, PointElement, LinearScale, CategoryScale, Tooltip);
|
||||
|
||||
function LineChart07({
|
||||
data,
|
||||
width,
|
||||
height
|
||||
}) {
|
||||
|
||||
const canvas = useRef(null);
|
||||
|
||||
useEffect(() => {
|
||||
const ctx = canvas.current;
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
const chart = new Chart(ctx, {
|
||||
type: 'line',
|
||||
data: data,
|
||||
options: {
|
||||
layout: {
|
||||
padding: {
|
||||
top: 12,
|
||||
bottom: 16,
|
||||
left: 20,
|
||||
right: 20,
|
||||
},
|
||||
},
|
||||
scales: {
|
||||
y: {
|
||||
beginAtZero: true,
|
||||
grid: {
|
||||
drawBorder: false,
|
||||
},
|
||||
ticks: {
|
||||
maxTicksLimit: 7,
|
||||
callback: (value) => formatValue(value),
|
||||
},
|
||||
},
|
||||
x: {
|
||||
grid: {
|
||||
display: false,
|
||||
drawBorder: false,
|
||||
},
|
||||
ticks: {
|
||||
autoSkipPadding: 48,
|
||||
maxRotation: 0,
|
||||
align: 'end',
|
||||
},
|
||||
},
|
||||
},
|
||||
plugins: {
|
||||
tooltip: {
|
||||
callbacks: {
|
||||
title: () => false, // Disable tooltip title
|
||||
label: (context) => formatValue(context.parsed.y),
|
||||
},
|
||||
},
|
||||
legend: {
|
||||
display: false,
|
||||
},
|
||||
},
|
||||
interaction: {
|
||||
intersect: false,
|
||||
mode: 'nearest',
|
||||
},
|
||||
maintainAspectRatio: false,
|
||||
},
|
||||
});
|
||||
return () => chart.destroy();
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<canvas ref={canvas} width={width} height={height}></canvas>
|
||||
);
|
||||
}
|
||||
|
||||
export default LineChart07;
|
||||
@@ -1,84 +0,0 @@
|
||||
import React, { useRef, useEffect } from 'react';
|
||||
|
||||
import {
|
||||
Chart, LineController, LineElement, Filler, PointElement, LinearScale, TimeScale, Tooltip,
|
||||
} from 'chart.js';
|
||||
import 'chartjs-adapter-moment';
|
||||
|
||||
// Import utilities
|
||||
import { formatValue } from '../utils/Utils';
|
||||
|
||||
Chart.register(LineController, LineElement, Filler, PointElement, LinearScale, TimeScale, Tooltip);
|
||||
|
||||
function LineChart08({
|
||||
data,
|
||||
width,
|
||||
height
|
||||
}) {
|
||||
|
||||
const canvas = useRef(null);
|
||||
|
||||
useEffect(() => {
|
||||
const ctx = canvas.current;
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
const chart = new Chart(ctx, {
|
||||
type: 'line',
|
||||
data: data,
|
||||
options: {
|
||||
layout: {
|
||||
padding: {
|
||||
top: 16,
|
||||
bottom: 16,
|
||||
left: 20,
|
||||
right: 20,
|
||||
},
|
||||
},
|
||||
scales: {
|
||||
y: {
|
||||
beginAtZero: true,
|
||||
grid: {
|
||||
drawBorder: false,
|
||||
drawTicks: false,
|
||||
},
|
||||
ticks: {
|
||||
maxTicksLimit: 2,
|
||||
display: false,
|
||||
},
|
||||
},
|
||||
x: {
|
||||
type: 'time',
|
||||
time: {
|
||||
parser: 'MM-DD-YYYY',
|
||||
unit: 'month',
|
||||
},
|
||||
display: false,
|
||||
},
|
||||
},
|
||||
plugins: {
|
||||
tooltip: {
|
||||
callbacks: {
|
||||
title: () => false, // Disable tooltip title
|
||||
label: (context) => formatValue(context.parsed.y),
|
||||
},
|
||||
},
|
||||
legend: {
|
||||
display: false,
|
||||
},
|
||||
},
|
||||
interaction: {
|
||||
intersect: false,
|
||||
mode: 'nearest',
|
||||
},
|
||||
maintainAspectRatio: false,
|
||||
},
|
||||
});
|
||||
return () => chart.destroy();
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<canvas ref={canvas} width={width} height={height}></canvas>
|
||||
);
|
||||
}
|
||||
|
||||
export default LineChart08;
|
||||
@@ -1,69 +0,0 @@
|
||||
import React, { useRef, useEffect } from 'react';
|
||||
|
||||
import {
|
||||
Chart, LineController, LineElement, Filler, PointElement, LinearScale, TimeScale, Tooltip,
|
||||
} from 'chart.js';
|
||||
import 'chartjs-adapter-moment';
|
||||
|
||||
// Import utilities
|
||||
import { formatValue } from '../utils/Utils';
|
||||
|
||||
Chart.register(LineController, LineElement, Filler, PointElement, LinearScale, TimeScale, Tooltip);
|
||||
|
||||
function LineChart09({
|
||||
data,
|
||||
width,
|
||||
height
|
||||
}) {
|
||||
|
||||
const canvas = useRef(null);
|
||||
|
||||
useEffect(() => {
|
||||
const ctx = canvas.current;
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
const chart = new Chart(ctx, {
|
||||
type: 'line',
|
||||
data: data,
|
||||
options: {
|
||||
scales: {
|
||||
y: {
|
||||
display: false,
|
||||
beginAtZero: true,
|
||||
},
|
||||
x: {
|
||||
type: 'time',
|
||||
time: {
|
||||
parser: 'MM-DD-YYYY',
|
||||
unit: 'month',
|
||||
},
|
||||
display: false,
|
||||
},
|
||||
},
|
||||
plugins: {
|
||||
tooltip: {
|
||||
callbacks: {
|
||||
title: () => false, // Disable tooltip title
|
||||
label: (context) => formatValue(context.parsed.y),
|
||||
},
|
||||
},
|
||||
legend: {
|
||||
display: false,
|
||||
},
|
||||
},
|
||||
interaction: {
|
||||
intersect: false,
|
||||
mode: 'nearest',
|
||||
},
|
||||
maintainAspectRatio: false,
|
||||
},
|
||||
});
|
||||
return () => chart.destroy();
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<canvas ref={canvas} width={width} height={height}></canvas>
|
||||
);
|
||||
}
|
||||
|
||||
export default LineChart09;
|
||||
@@ -1,117 +0,0 @@
|
||||
import React, { useRef, useEffect } from 'react';
|
||||
|
||||
import {
|
||||
Chart, PieController, ArcElement, TimeScale, Tooltip,
|
||||
} from 'chart.js';
|
||||
import 'chartjs-adapter-moment';
|
||||
|
||||
// Import utilities
|
||||
import { tailwindConfig } from '../utils/Utils';
|
||||
|
||||
Chart.register(PieController, ArcElement, TimeScale, Tooltip);
|
||||
|
||||
function PieChart({
|
||||
data,
|
||||
width,
|
||||
height
|
||||
}) {
|
||||
|
||||
const canvas = useRef(null);
|
||||
const legend = useRef(null);
|
||||
|
||||
useEffect(() => {
|
||||
const ctx = canvas.current;
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
const chart = new Chart(ctx, {
|
||||
type: 'pie',
|
||||
data: data,
|
||||
options: {
|
||||
layout: {
|
||||
padding: {
|
||||
top: 4,
|
||||
bottom: 4,
|
||||
left: 24,
|
||||
right: 24,
|
||||
},
|
||||
},
|
||||
plugins: {
|
||||
legend: {
|
||||
display: false,
|
||||
},
|
||||
},
|
||||
interaction: {
|
||||
intersect: false,
|
||||
mode: 'nearest',
|
||||
},
|
||||
animation: {
|
||||
duration: 200,
|
||||
},
|
||||
maintainAspectRatio: false,
|
||||
},
|
||||
plugins: [
|
||||
{
|
||||
id: 'htmlLegend',
|
||||
afterUpdate(c, args, options) {
|
||||
const ul = legend.current;
|
||||
if (!ul) return;
|
||||
// Remove old legend items
|
||||
while (ul.firstChild) {
|
||||
ul.firstChild.remove();
|
||||
}
|
||||
// Reuse the built-in legendItems generator
|
||||
const items = c.options.plugins.legend.labels.generateLabels(c);
|
||||
items.forEach((item) => {
|
||||
const li = document.createElement('li');
|
||||
li.style.margin = tailwindConfig().theme.margin[1.5];
|
||||
// Button element
|
||||
const button = document.createElement('button');
|
||||
button.style.display = 'inline-flex';
|
||||
button.style.alignItems = 'center';
|
||||
button.style.opacity = item.hidden ? '.3' : '';
|
||||
button.onclick = () => {
|
||||
c.toggleDataVisibility(item.index, !item.index);
|
||||
c.update();
|
||||
};
|
||||
// Color box
|
||||
const box = document.createElement('span');
|
||||
box.style.display = 'block';
|
||||
box.style.width = tailwindConfig().theme.width[3];
|
||||
box.style.height = tailwindConfig().theme.height[3];
|
||||
box.style.borderRadius = tailwindConfig().theme.borderRadius.full;
|
||||
box.style.marginRight = tailwindConfig().theme.margin[1.5];
|
||||
box.style.borderWidth = '3px';
|
||||
box.style.borderColor = item.fillStyle;
|
||||
box.style.pointerEvents = 'none';
|
||||
// Label
|
||||
const label = document.createElement('span');
|
||||
label.style.color = tailwindConfig().theme.colors.slate[500];
|
||||
label.style.fontSize = tailwindConfig().theme.fontSize.sm[0];
|
||||
label.style.lineHeight = tailwindConfig().theme.fontSize.sm[1].lineHeight;
|
||||
const labelText = document.createTextNode(item.text);
|
||||
label.appendChild(labelText);
|
||||
li.appendChild(button);
|
||||
button.appendChild(box);
|
||||
button.appendChild(label);
|
||||
ul.appendChild(li);
|
||||
});
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
return () => chart.destroy();
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="grow flex flex-col justify-center">
|
||||
<div>
|
||||
<canvas ref={canvas} width={width} height={height}></canvas>
|
||||
</div>
|
||||
<div className="px-5 py-4">
|
||||
<ul ref={legend} className="flex flex-wrap justify-center -m-1" />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default PieChart;
|
||||
@@ -1,113 +0,0 @@
|
||||
import React, { useRef, useEffect } from 'react';
|
||||
|
||||
import {
|
||||
Chart, PolarAreaController, RadialLinearScale, Tooltip, Legend,
|
||||
} from 'chart.js';
|
||||
import 'chartjs-adapter-moment';
|
||||
|
||||
// Import utilities
|
||||
import { tailwindConfig } from '../utils/Utils';
|
||||
|
||||
Chart.register(PolarAreaController, RadialLinearScale, Tooltip, Legend);
|
||||
|
||||
function PolarChart({
|
||||
data,
|
||||
width,
|
||||
height
|
||||
}) {
|
||||
|
||||
const canvas = useRef(null);
|
||||
const legend = useRef(null);
|
||||
|
||||
useEffect(() => {
|
||||
const ctx = canvas.current;
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
const chart = new Chart(ctx, {
|
||||
type: 'polarArea',
|
||||
data: data,
|
||||
options: {
|
||||
layout: {
|
||||
padding: 24,
|
||||
},
|
||||
plugins: {
|
||||
legend: {
|
||||
display: false,
|
||||
},
|
||||
},
|
||||
interaction: {
|
||||
intersect: false,
|
||||
mode: 'nearest',
|
||||
},
|
||||
animation: {
|
||||
duration: 500,
|
||||
},
|
||||
maintainAspectRatio: false,
|
||||
resizeDelay: 200,
|
||||
},
|
||||
plugins: [{
|
||||
id: 'htmlLegend',
|
||||
afterUpdate(c, args, options) {
|
||||
const ul = legend.current
|
||||
if (!ul) return
|
||||
// Remove old legend items
|
||||
while (ul.firstChild) {
|
||||
ul.firstChild.remove()
|
||||
}
|
||||
// Reuse the built-in legendItems generator
|
||||
const items = c.options.plugins.legend.labels.generateLabels(c)
|
||||
items.forEach((item) => {
|
||||
const li = document.createElement('li')
|
||||
li.style.margin = tailwindConfig().theme.margin[1]
|
||||
// Button element
|
||||
const button = document.createElement('button')
|
||||
button.classList.add('btn-xs')
|
||||
button.style.backgroundColor = tailwindConfig().theme.colors.white
|
||||
button.style.borderWidth = tailwindConfig().theme.borderWidth[1]
|
||||
button.style.borderColor = tailwindConfig().theme.colors.slate[200]
|
||||
button.style.color = tailwindConfig().theme.colors.slate[500]
|
||||
button.style.boxShadow = tailwindConfig().theme.boxShadow.md
|
||||
button.style.opacity = item.hidden ? '.3' : ''
|
||||
button.onclick = () => {
|
||||
c.toggleDataVisibility(item.index, !item.index)
|
||||
c.update()
|
||||
}
|
||||
// Color box
|
||||
const box = document.createElement('span')
|
||||
box.style.display = 'block'
|
||||
box.style.width = tailwindConfig().theme.width[2]
|
||||
box.style.height = tailwindConfig().theme.height[2]
|
||||
box.style.backgroundColor = item.fillStyle
|
||||
box.style.borderRadius = tailwindConfig().theme.borderRadius.sm
|
||||
box.style.marginRight = tailwindConfig().theme.margin[1]
|
||||
box.style.pointerEvents = 'none'
|
||||
// Label
|
||||
const label = document.createElement('span')
|
||||
label.style.display = 'flex'
|
||||
label.style.alignItems = 'center'
|
||||
const labelText = document.createTextNode(item.text)
|
||||
label.appendChild(labelText)
|
||||
li.appendChild(button)
|
||||
button.appendChild(box)
|
||||
button.appendChild(label)
|
||||
ul.appendChild(li)
|
||||
})
|
||||
},
|
||||
}],
|
||||
});
|
||||
return () => chart.destroy();
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="grow flex flex-col justify-center">
|
||||
<div>
|
||||
<canvas ref={canvas} width={width} height={height}></canvas>
|
||||
</div>
|
||||
<div className="px-5 pt-2 pb-6">
|
||||
<ul ref={legend} className="flex flex-wrap justify-center -m-1"></ul>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default PolarChart;
|
||||
@@ -1,120 +0,0 @@
|
||||
import React, { useRef, useEffect } from 'react';
|
||||
|
||||
import {
|
||||
Chart, LineController, LineElement, Filler, PointElement, LinearScale, TimeScale, Tooltip,
|
||||
} from 'chart.js';
|
||||
import 'chartjs-adapter-moment';
|
||||
|
||||
// Import utilities
|
||||
import { tailwindConfig, formatValue } from '../utils/Utils';
|
||||
|
||||
Chart.register(LineController, LineElement, Filler, PointElement, LinearScale, TimeScale, Tooltip);
|
||||
|
||||
function RealtimeChart({
|
||||
data,
|
||||
width,
|
||||
height
|
||||
}) {
|
||||
|
||||
const canvas = useRef(null);
|
||||
const chartValue = useRef(null);
|
||||
const chartDeviation = useRef(null);
|
||||
|
||||
useEffect(() => {
|
||||
const ctx = canvas.current;
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
const chart = new Chart(ctx, {
|
||||
type: 'line',
|
||||
data: data,
|
||||
options: {
|
||||
layout: {
|
||||
padding: 20,
|
||||
},
|
||||
scales: {
|
||||
y: {
|
||||
grid: {
|
||||
drawBorder: false,
|
||||
},
|
||||
suggestedMin: 30,
|
||||
suggestedMax: 80,
|
||||
ticks: {
|
||||
maxTicksLimit: 5,
|
||||
callback: (value) => formatValue(value),
|
||||
},
|
||||
},
|
||||
x: {
|
||||
type: 'time',
|
||||
time: {
|
||||
parser: 'hh:mm:ss',
|
||||
unit: 'second',
|
||||
tooltipFormat: 'MMM DD, H:mm:ss a',
|
||||
displayFormats: {
|
||||
second: 'H:mm:ss',
|
||||
},
|
||||
},
|
||||
grid: {
|
||||
display: false,
|
||||
drawBorder: false,
|
||||
},
|
||||
ticks: {
|
||||
autoSkipPadding: 48,
|
||||
maxRotation: 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
plugins: {
|
||||
legend: {
|
||||
display: false,
|
||||
},
|
||||
tooltip: {
|
||||
titleFont: {
|
||||
weight: '600',
|
||||
},
|
||||
callbacks: {
|
||||
label: (context) => formatValue(context.parsed.y),
|
||||
},
|
||||
},
|
||||
},
|
||||
interaction: {
|
||||
intersect: false,
|
||||
mode: 'nearest',
|
||||
},
|
||||
animation: false,
|
||||
maintainAspectRatio: false,
|
||||
resizeDelay: 200,
|
||||
},
|
||||
});
|
||||
return () => chart.destroy();
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [data]);
|
||||
|
||||
// Update header values
|
||||
useEffect(() => {
|
||||
const currentValue = data.datasets[0].data[data.datasets[0].data.length - 1];
|
||||
const previousValue = data.datasets[0].data[data.datasets[0].data.length - 2];
|
||||
const diff = ((currentValue - previousValue) / previousValue) * 100;
|
||||
chartValue.current.innerHTML = data.datasets[0].data[data.datasets[0].data.length - 1];
|
||||
if (diff < 0) {
|
||||
chartDeviation.current.style.backgroundColor = tailwindConfig().theme.colors.yellow[500];
|
||||
} else {
|
||||
chartDeviation.current.style.backgroundColor = tailwindConfig().theme.colors.emerald[500];
|
||||
}
|
||||
chartDeviation.current.innerHTML = `${diff > 0 ? '+' : ''}${diff.toFixed(2)}%`;
|
||||
}, [data]);
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<div className="px-5 py-3">
|
||||
<div className="flex items-start">
|
||||
<div className="text-3xl font-bold text-slate-800 mr-2 tabular-nums">$<span ref={chartValue}>57.81</span></div>
|
||||
<div ref={chartDeviation} className="text-sm font-semibold text-white px-1.5 rounded-full"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="grow">
|
||||
<canvas ref={canvas} data={data} width={width} height={height}></canvas>
|
||||
</div>
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
|
||||
export default RealtimeChart;
|
||||
@@ -1,26 +0,0 @@
|
||||
import React, { useState } from 'react';
|
||||
|
||||
function AccordionBasic(props) {
|
||||
|
||||
const [open, setOpen] = useState(false);
|
||||
|
||||
return (
|
||||
<div className="px-5 py-4 rounded-sm border border-slate-200">
|
||||
<button
|
||||
className="flex items-center justify-between w-full group mb-1"
|
||||
aria-expanded={open}
|
||||
onClick={() => setOpen(!open)}
|
||||
>
|
||||
<div className="text-sm text-slate-800 font-medium">{props.title}</div>
|
||||
<svg className={`w-8 h-8 shrink-0 fill-current text-slate-400 group-hover:text-slate-500 ml-3 ${open && 'rotate-180'}`} viewBox="0 0 32 32">
|
||||
<path d="M16 20l-5.4-5.4 1.4-1.4 4 4 4-4 1.4 1.4z" />
|
||||
</svg>
|
||||
</button>
|
||||
<div className={`text-sm ${!open && 'hidden'}`}>
|
||||
{props.children}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default AccordionBasic;
|
||||
@@ -1,73 +0,0 @@
|
||||
import React, { useState } from 'react';
|
||||
|
||||
function AccordionTableItem(props) {
|
||||
|
||||
const [open, setOpen] = useState(false);
|
||||
|
||||
return (
|
||||
<tbody className="text-sm">
|
||||
<tr>
|
||||
<td className="px-2 first:pl-5 last:pr-5 py-3 whitespace-nowrap">
|
||||
<div className="flex items-center text-slate-800">
|
||||
<div className="w-10 h-10 shrink-0 flex items-center justify-center bg-slate-100 rounded-full mr-2 sm:mr-3">
|
||||
<img className="rounded-full ml-1" src={props.image} width="40" height="40" alt={props.customer} />
|
||||
</div>
|
||||
<div className="font-medium text-slate-800">{props.customer}</div>
|
||||
</div>
|
||||
</td>
|
||||
<td className="px-2 first:pl-5 last:pr-5 py-3 whitespace-nowrap">
|
||||
<div className="text-left font-medium text-emerald-500">{props.total}</div>
|
||||
</td>
|
||||
<td className="px-2 first:pl-5 last:pr-5 py-3 whitespace-nowrap">
|
||||
<div className="inline-flex font-medium bg-amber-100 text-amber-600 rounded-full text-center px-2.5 py-0.5">{props.status}</div>
|
||||
</td>
|
||||
<td className="px-2 first:pl-5 last:pr-5 py-3 whitespace-nowrap">
|
||||
<div className="text-center">{props.items}</div>
|
||||
</td>
|
||||
<td className="px-2 first:pl-5 last:pr-5 py-3 whitespace-nowrap">
|
||||
<div className="text-left">{props.location}</div>
|
||||
</td>
|
||||
<td className="px-2 first:pl-5 last:pr-5 py-3 whitespace-nowrap">
|
||||
<div className="flex items-center">
|
||||
<svg className="w-4 h-4 fill-current text-slate-400 shrink-0 mr-2" viewBox="0 0 16 16">
|
||||
<path d="M4.3 4.5c1.9-1.9 5.1-1.9 7 0 .7.7 1.2 1.7 1.4 2.7l2-.3c-.2-1.5-.9-2.8-1.9-3.8C10.1.4 5.7.4 2.9 3.1L.7.9 0 7.3l6.4-.7-2.1-2.1zM15.6 8.7l-6.4.7 2.1 2.1c-1.9 1.9-5.1 1.9-7 0-.7-.7-1.2-1.7-1.4-2.7l-2 .3c.2 1.5.9 2.8 1.9 3.8 1.4 1.4 3.1 2 4.9 2 1.8 0 3.6-.7 4.9-2l2.2 2.2.8-6.4z" />
|
||||
</svg>
|
||||
<div>{props.type}</div>
|
||||
</div>
|
||||
</td>
|
||||
<td className="px-2 first:pl-5 last:pr-5 py-3 whitespace-nowrap w-px">
|
||||
<div className="flex items-center">
|
||||
<button
|
||||
className={`text-slate-400 hover:text-slate-500 transform ${open && 'rotate-180'}`}
|
||||
aria-expanded={open}
|
||||
onClick={() => setOpen(!open)}
|
||||
aria-controls={`description-${props.id}`}
|
||||
>
|
||||
<span className="sr-only">Menu</span>
|
||||
<svg className="w-8 h-8 fill-current" viewBox="0 0 32 32">
|
||||
<path d="M16 20l-5.4-5.4 1.4-1.4 4 4 4-4 1.4 1.4z" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
{/*
|
||||
Example of content revealing when clicking the button on the right side:
|
||||
Note that you must set a "colSpan" attribute on the <td> element,
|
||||
and it should match the number of columns in your table
|
||||
*/}
|
||||
<tr id={`description-${props.id}`} role="region" className={`${!open && 'hidden'}`}>
|
||||
<td colSpan="10" className="px-2 first:pl-5 last:pr-5 py-3">
|
||||
<div className="flex items-center bg-slate-50 p-3 -mt-3">
|
||||
<svg className="w-4 h-4 shrink-0 fill-current text-slate-400 mr-2">
|
||||
<path d="M1 16h3c.3 0 .5-.1.7-.3l11-11c.4-.4.4-1 0-1.4l-3-3c-.4-.4-1-.4-1.4 0l-11 11c-.2.2-.3.4-.3.7v3c0 .6.4 1 1 1zm1-3.6l10-10L13.6 4l-10 10H2v-1.6z" />
|
||||
</svg>
|
||||
<div className="italic">{props.description}</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
);
|
||||
}
|
||||
|
||||
export default AccordionTableItem;
|
||||
@@ -1,66 +0,0 @@
|
||||
import React, { useState } from 'react';
|
||||
|
||||
function AccordionTableRichItem(props) {
|
||||
|
||||
const [open, setOpen] = useState(false);
|
||||
|
||||
return (
|
||||
<tbody className="text-sm">
|
||||
<tr>
|
||||
<td className="px-2 first:pl-5 last:pr-5 py-3 whitespace-nowrap">
|
||||
<div className="flex items-center text-slate-800">
|
||||
<div className="w-10 h-10 shrink-0 flex items-center justify-center bg-slate-100 rounded-full mr-2 sm:mr-3">
|
||||
<img className="rounded-full ml-1" src={props.image} width="40" height="40" alt={props.customer} />
|
||||
</div>
|
||||
<div className="font-medium text-slate-800">{props.customer}</div>
|
||||
</div>
|
||||
</td>
|
||||
<td className="px-2 first:pl-5 last:pr-5 py-3 whitespace-nowrap">
|
||||
<div className="text-left">{props.email}</div>
|
||||
</td>
|
||||
<td className="px-2 first:pl-5 last:pr-5 py-3 whitespace-nowrap">
|
||||
<div className="text-left">{props.location}</div>
|
||||
</td>
|
||||
<td className="px-2 first:pl-5 last:pr-5 py-3 whitespace-nowrap">
|
||||
<div className="text-left">{props.date}</div>
|
||||
</td>
|
||||
<td className="px-2 first:pl-5 last:pr-5 py-3 whitespace-nowrap">
|
||||
<div className="text-left text-emerald-500 font-medium">{props.amount}</div>
|
||||
</td>
|
||||
<td className="px-2 first:pl-5 last:pr-5 py-3 whitespace-nowrap w-px">
|
||||
<div className="flex items-center">
|
||||
<button
|
||||
className={`text-slate-400 hover:text-slate-500 transform ${open && 'rotate-180'}`}
|
||||
aria-expanded={open}
|
||||
onClick={() => setOpen(!open)}
|
||||
aria-controls={`description-${props.id}`}
|
||||
>
|
||||
<span className="sr-only">Menu</span>
|
||||
<svg className="w-8 h-8 fill-current" viewBox="0 0 32 32">
|
||||
<path d="M16 20l-5.4-5.4 1.4-1.4 4 4 4-4 1.4 1.4z" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
{/*
|
||||
Example of content revealing when clicking the button on the right side:
|
||||
Note that you must set a "colSpan" attribute on the <td> element,
|
||||
and it should match the number of columns in your table
|
||||
*/}
|
||||
<tr id={`description-${props.id}`} role="region" className={`${!open && 'hidden'}`}>
|
||||
<td colSpan="10" className="px-2 first:pl-5 last:pr-5 py-3">
|
||||
<div className="bg-slate-50 p-3 -mt-3">
|
||||
<div className="text-sm mb-3">
|
||||
<div className="font-medium text-slate-800 mb-1">{props.descriptionTitle}</div>
|
||||
<div>{props.descriptionBody}</div>
|
||||
</div>
|
||||
<button className="btn-xs bg-indigo-500 hover:bg-indigo-600 text-white">Approve</button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
);
|
||||
}
|
||||
|
||||
export default AccordionTableRichItem;
|
||||
@@ -1,38 +0,0 @@
|
||||
import React from 'react';
|
||||
import Flatpickr from 'react-flatpickr';
|
||||
|
||||
function Datepicker({
|
||||
align
|
||||
}) {
|
||||
|
||||
const options = {
|
||||
mode: 'range',
|
||||
static: true,
|
||||
monthSelectorType: 'static',
|
||||
dateFormat: 'M j, Y',
|
||||
defaultDate: [new Date().setDate(new Date().getDate() - 6), new Date()],
|
||||
prevArrow: '<svg class="fill-current" width="7" height="11" viewBox="0 0 7 11"><path d="M5.4 10.8l1.4-1.4-4-4 4-4L5.4 0 0 5.4z" /></svg>',
|
||||
nextArrow: '<svg class="fill-current" width="7" height="11" viewBox="0 0 7 11"><path d="M1.4 10.8L0 9.4l4-4-4-4L1.4 0l5.4 5.4z" /></svg>',
|
||||
onReady: (selectedDates, dateStr, instance) => {
|
||||
instance.element.value = dateStr.replace('to', '-');
|
||||
const customClass = (align) ? align : '';
|
||||
instance.calendarContainer.classList.add(`flatpickr-${customClass}`);
|
||||
},
|
||||
onChange: (selectedDates, dateStr, instance) => {
|
||||
instance.element.value = dateStr.replace('to', '-');
|
||||
},
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="relative">
|
||||
<Flatpickr className="form-input pl-9 text-slate-500 hover:text-slate-600 font-medium focus:border-slate-300 w-60" options={options} />
|
||||
<div className="absolute inset-0 right-auto flex items-center pointer-events-none">
|
||||
<svg className="w-4 h-4 fill-current text-slate-500 ml-3" viewBox="0 0 16 16">
|
||||
<path d="M15 2h-2V0h-2v2H9V0H7v2H5V0H3v2H1a1 1 0 00-1 1v12a1 1 0 001 1h14a1 1 0 001-1V3a1 1 0 00-1-1zm-1 12H2V6h12v8z" />
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default Datepicker;
|
||||
@@ -1,75 +0,0 @@
|
||||
import React, { useState, useRef, useEffect } from 'react';
|
||||
import Transition from '../utils/Transition';
|
||||
|
||||
function DropdownEditMenu({
|
||||
children,
|
||||
align,
|
||||
...rest
|
||||
}) {
|
||||
|
||||
const [dropdownOpen, setDropdownOpen] = useState(false);
|
||||
|
||||
const trigger = useRef(null);
|
||||
const dropdown = useRef(null);
|
||||
|
||||
// close on click outside
|
||||
useEffect(() => {
|
||||
const clickHandler = ({ target }) => {
|
||||
if (!dropdown.current) return;
|
||||
if (!dropdownOpen || dropdown.current.contains(target) || trigger.current.contains(target)) return;
|
||||
setDropdownOpen(false);
|
||||
};
|
||||
document.addEventListener('click', clickHandler);
|
||||
return () => document.removeEventListener('click', clickHandler);
|
||||
});
|
||||
|
||||
// close if the esc key is pressed
|
||||
useEffect(() => {
|
||||
const keyHandler = ({ keyCode }) => {
|
||||
if (!dropdownOpen || keyCode !== 27) return;
|
||||
setDropdownOpen(false);
|
||||
};
|
||||
document.addEventListener('keydown', keyHandler);
|
||||
return () => document.removeEventListener('keydown', keyHandler);
|
||||
});
|
||||
|
||||
return (
|
||||
<div {...rest}>
|
||||
<button
|
||||
ref={trigger}
|
||||
className={`bg-white text-slate-400 hover:text-slate-500 rounded-full ${dropdownOpen && 'bg-slate-100 text-slate-500'}`}
|
||||
aria-haspopup="true"
|
||||
onClick={() => setDropdownOpen(!dropdownOpen)}
|
||||
aria-expanded={dropdownOpen}
|
||||
>
|
||||
<span className="sr-only">Menu</span>
|
||||
<svg className="w-8 h-8 fill-current" viewBox="0 0 32 32">
|
||||
<circle cx="16" cy="16" r="2" />
|
||||
<circle cx="10" cy="16" r="2" />
|
||||
<circle cx="22" cy="16" r="2" />
|
||||
</svg>
|
||||
</button>
|
||||
<Transition
|
||||
show={dropdownOpen}
|
||||
tag="div"
|
||||
className={`origin-top-right z-10 absolute top-full min-w-36 bg-white border border-slate-200 py-1.5 rounded shadow-lg overflow-hidden mt-1 ${align === 'right' ? 'right-0' : 'left-0'}`}
|
||||
enter="transition ease-out duration-200 transform"
|
||||
enterStart="opacity-0 -translate-y-2"
|
||||
enterEnd="opacity-100 translate-y-0"
|
||||
leave="transition ease-out duration-200"
|
||||
leaveStart="opacity-100"
|
||||
leaveEnd="opacity-0"
|
||||
>
|
||||
<ul
|
||||
ref={dropdown}
|
||||
onFocus={() => setDropdownOpen(true)}
|
||||
onBlur={() => setDropdownOpen(false)}
|
||||
>
|
||||
{children}
|
||||
</ul>
|
||||
</Transition>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default DropdownEditMenu;
|
||||
@@ -1,115 +0,0 @@
|
||||
import React, { useState, useRef, useEffect } from 'react';
|
||||
import Transition from '../utils/Transition';
|
||||
|
||||
function DropdownFilter({
|
||||
align
|
||||
}) {
|
||||
|
||||
const [dropdownOpen, setDropdownOpen] = useState(false);
|
||||
|
||||
const trigger = useRef(null);
|
||||
const dropdown = useRef(null);
|
||||
|
||||
// close on click outside
|
||||
useEffect(() => {
|
||||
const clickHandler = ({ target }) => {
|
||||
if (!dropdown.current) return;
|
||||
if (!dropdownOpen || dropdown.current.contains(target) || trigger.current.contains(target)) return;
|
||||
setDropdownOpen(false);
|
||||
};
|
||||
document.addEventListener('click', clickHandler);
|
||||
return () => document.removeEventListener('click', clickHandler);
|
||||
});
|
||||
|
||||
// close if the esc key is pressed
|
||||
useEffect(() => {
|
||||
const keyHandler = ({ keyCode }) => {
|
||||
if (!dropdownOpen || keyCode !== 27) return;
|
||||
setDropdownOpen(false);
|
||||
};
|
||||
document.addEventListener('keydown', keyHandler);
|
||||
return () => document.removeEventListener('keydown', keyHandler);
|
||||
});
|
||||
|
||||
return (
|
||||
<div className="relative inline-flex">
|
||||
<button
|
||||
ref={trigger}
|
||||
className="btn bg-white border-slate-200 hover:border-slate-300 text-slate-500 hover:text-slate-600"
|
||||
aria-haspopup="true"
|
||||
onClick={() => setDropdownOpen(!dropdownOpen)}
|
||||
aria-expanded={dropdownOpen}
|
||||
>
|
||||
<span className="sr-only">Filter</span><wbr />
|
||||
<svg className="w-4 h-4 fill-current" viewBox="0 0 16 16">
|
||||
<path d="M9 15H7a1 1 0 010-2h2a1 1 0 010 2zM11 11H5a1 1 0 010-2h6a1 1 0 010 2zM13 7H3a1 1 0 010-2h10a1 1 0 010 2zM15 3H1a1 1 0 010-2h14a1 1 0 010 2z" />
|
||||
</svg>
|
||||
</button>
|
||||
<Transition
|
||||
show={dropdownOpen}
|
||||
tag="div"
|
||||
className={`origin-top-right z-10 absolute top-full min-w-56 bg-white border border-slate-200 pt-1.5 rounded shadow-lg overflow-hidden mt-1 ${align === 'right' ? 'right-0' : 'left-0'}`}
|
||||
enter="transition ease-out duration-200 transform"
|
||||
enterStart="opacity-0 -translate-y-2"
|
||||
enterEnd="opacity-100 translate-y-0"
|
||||
leave="transition ease-out duration-200"
|
||||
leaveStart="opacity-100"
|
||||
leaveEnd="opacity-0"
|
||||
>
|
||||
<div ref={dropdown}>
|
||||
<div className="text-xs font-semibold text-slate-400 uppercase pt-1.5 pb-2 px-4">Filters</div>
|
||||
<ul className="mb-4">
|
||||
<li className="py-1 px-3">
|
||||
<label className="flex items-center">
|
||||
<input type="checkbox" className="form-checkbox" />
|
||||
<span className="text-sm font-medium ml-2">Direct VS Indirect</span>
|
||||
</label>
|
||||
</li>
|
||||
<li className="py-1 px-3">
|
||||
<label className="flex items-center">
|
||||
<input type="checkbox" className="form-checkbox" />
|
||||
<span className="text-sm font-medium ml-2">Real Time Value</span>
|
||||
</label>
|
||||
</li>
|
||||
<li className="py-1 px-3">
|
||||
<label className="flex items-center">
|
||||
<input type="checkbox" className="form-checkbox" />
|
||||
<span className="text-sm font-medium ml-2">Top Channels</span>
|
||||
</label>
|
||||
</li>
|
||||
<li className="py-1 px-3">
|
||||
<label className="flex items-center">
|
||||
<input type="checkbox" className="form-checkbox" />
|
||||
<span className="text-sm font-medium ml-2">Sales VS Refunds</span>
|
||||
</label>
|
||||
</li>
|
||||
<li className="py-1 px-3">
|
||||
<label className="flex items-center">
|
||||
<input type="checkbox" className="form-checkbox" />
|
||||
<span className="text-sm font-medium ml-2">Last Order</span>
|
||||
</label>
|
||||
</li>
|
||||
<li className="py-1 px-3">
|
||||
<label className="flex items-center">
|
||||
<input type="checkbox" className="form-checkbox" />
|
||||
<span className="text-sm font-medium ml-2">Total Spent</span>
|
||||
</label>
|
||||
</li>
|
||||
</ul>
|
||||
<div className="py-2 px-3 border-t border-slate-200 bg-slate-50">
|
||||
<ul className="flex items-center justify-between">
|
||||
<li>
|
||||
<button className="btn-xs bg-white border-slate-200 hover:border-slate-300 text-slate-500 hover:text-slate-600">Clear</button>
|
||||
</li>
|
||||
<li>
|
||||
<button className="btn-xs bg-indigo-500 hover:bg-indigo-600 text-white" onClick={() => setDropdownOpen(false)} onBlur={() => setDropdownOpen(false)}>Apply</button>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</Transition>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default DropdownFilter;
|
||||
@@ -1,111 +0,0 @@
|
||||
import React, { useState, useRef, useEffect } from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
import Transition from '../utils/Transition';
|
||||
|
||||
function DropdownHelp({
|
||||
align
|
||||
}) {
|
||||
|
||||
const [dropdownOpen, setDropdownOpen] = useState(false);
|
||||
|
||||
const trigger = useRef(null);
|
||||
const dropdown = useRef(null);
|
||||
|
||||
// close on click outside
|
||||
useEffect(() => {
|
||||
const clickHandler = ({ target }) => {
|
||||
if (!dropdown.current) return;
|
||||
if (!dropdownOpen || dropdown.current.contains(target) || trigger.current.contains(target)) return;
|
||||
setDropdownOpen(false);
|
||||
};
|
||||
document.addEventListener('click', clickHandler);
|
||||
return () => document.removeEventListener('click', clickHandler);
|
||||
});
|
||||
|
||||
// close if the esc key is pressed
|
||||
useEffect(() => {
|
||||
const keyHandler = ({ keyCode }) => {
|
||||
if (!dropdownOpen || keyCode !== 27) return;
|
||||
setDropdownOpen(false);
|
||||
};
|
||||
document.addEventListener('keydown', keyHandler);
|
||||
return () => document.removeEventListener('keydown', keyHandler);
|
||||
});
|
||||
|
||||
return (
|
||||
<div className="relative inline-flex">
|
||||
<button
|
||||
ref={trigger}
|
||||
className={`w-8 h-8 flex items-center justify-center bg-slate-100 hover:bg-slate-200 transition duration-150 rounded-full ${dropdownOpen && 'bg-slate-200'}`}
|
||||
aria-haspopup="true"
|
||||
onClick={() => setDropdownOpen(!dropdownOpen)}
|
||||
aria-expanded={dropdownOpen}
|
||||
>
|
||||
<span className="sr-only">Need help?</span>
|
||||
<svg className="w-4 h-4" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
|
||||
<path className="fill-current text-slate-500" d="M8 0C3.6 0 0 3.6 0 8s3.6 8 8 8 8-3.6 8-8-3.6-8-8-8zm0 12c-.6 0-1-.4-1-1s.4-1 1-1 1 .4 1 1-.4 1-1 1zm1-3H7V4h2v5z" />
|
||||
</svg>
|
||||
</button>
|
||||
|
||||
<Transition
|
||||
className={`origin-top-right z-10 absolute top-full min-w-44 bg-white border border-slate-200 py-1.5 rounded shadow-lg overflow-hidden mt-1 ${align === 'right' ? 'right-0' : 'left-0'}`}
|
||||
show={dropdownOpen}
|
||||
enter="transition ease-out duration-200 transform"
|
||||
enterStart="opacity-0 -translate-y-2"
|
||||
enterEnd="opacity-100 translate-y-0"
|
||||
leave="transition ease-out duration-200"
|
||||
leaveStart="opacity-100"
|
||||
leaveEnd="opacity-0"
|
||||
>
|
||||
<div
|
||||
ref={dropdown}
|
||||
onFocus={() => setDropdownOpen(true)}
|
||||
onBlur={() => setDropdownOpen(false)}
|
||||
>
|
||||
<div className="text-xs font-semibold text-slate-400 uppercase pt-1.5 pb-2 px-4">Need help?</div>
|
||||
<ul>
|
||||
<li>
|
||||
<Link
|
||||
className="font-medium text-sm text-indigo-500 hover:text-indigo-600 flex items-center py-1 px-3"
|
||||
to="#0"
|
||||
onClick={() => setDropdownOpen(!dropdownOpen)}
|
||||
>
|
||||
<svg className="w-3 h-3 fill-current text-indigo-300 shrink-0 mr-2" viewBox="0 0 12 12">
|
||||
<rect y="3" width="12" height="9" rx="1" />
|
||||
<path d="M2 0h8v2H2z" />
|
||||
</svg>
|
||||
<span>Documentation</span>
|
||||
</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Link
|
||||
className="font-medium text-sm text-indigo-500 hover:text-indigo-600 flex items-center py-1 px-3"
|
||||
to="#0"
|
||||
onClick={() => setDropdownOpen(!dropdownOpen)}
|
||||
>
|
||||
<svg className="w-3 h-3 fill-current text-indigo-300 shrink-0 mr-2" viewBox="0 0 12 12">
|
||||
<path d="M10.5 0h-9A1.5 1.5 0 000 1.5v9A1.5 1.5 0 001.5 12h9a1.5 1.5 0 001.5-1.5v-9A1.5 1.5 0 0010.5 0zM10 7L8.207 5.207l-3 3-1.414-1.414 3-3L5 2h5v5z" />
|
||||
</svg>
|
||||
<span>Support Site</span>
|
||||
</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Link
|
||||
className="font-medium text-sm text-indigo-500 hover:text-indigo-600 flex items-center py-1 px-3"
|
||||
to="#0"
|
||||
onClick={() => setDropdownOpen(!dropdownOpen)}
|
||||
>
|
||||
<svg className="w-3 h-3 fill-current text-indigo-300 shrink-0 mr-2" viewBox="0 0 12 12">
|
||||
<path d="M11.854.146a.5.5 0 00-.525-.116l-11 4a.5.5 0 00-.015.934l4.8 1.921 1.921 4.8A.5.5 0 007.5 12h.008a.5.5 0 00.462-.329l4-11a.5.5 0 00-.116-.525z" />
|
||||
</svg>
|
||||
<span>Contact us</span>
|
||||
</Link>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</Transition>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default DropdownHelp;
|
||||
@@ -1,106 +0,0 @@
|
||||
import React, { useState, useRef, useEffect } from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
import Transition from '../utils/Transition';
|
||||
|
||||
function DropdownNotifications({
|
||||
align
|
||||
}) {
|
||||
|
||||
const [dropdownOpen, setDropdownOpen] = useState(false);
|
||||
|
||||
const trigger = useRef(null);
|
||||
const dropdown = useRef(null);
|
||||
|
||||
// close on click outside
|
||||
useEffect(() => {
|
||||
const clickHandler = ({ target }) => {
|
||||
if (!dropdown.current) return;
|
||||
if (!dropdownOpen || dropdown.current.contains(target) || trigger.current.contains(target)) return;
|
||||
setDropdownOpen(false);
|
||||
};
|
||||
document.addEventListener('click', clickHandler);
|
||||
return () => document.removeEventListener('click', clickHandler);
|
||||
});
|
||||
|
||||
// close if the esc key is pressed
|
||||
useEffect(() => {
|
||||
const keyHandler = ({ keyCode }) => {
|
||||
if (!dropdownOpen || keyCode !== 27) return;
|
||||
setDropdownOpen(false);
|
||||
};
|
||||
document.addEventListener('keydown', keyHandler);
|
||||
return () => document.removeEventListener('keydown', keyHandler);
|
||||
});
|
||||
|
||||
return (
|
||||
<div className="relative inline-flex">
|
||||
<button
|
||||
ref={trigger}
|
||||
className={`w-8 h-8 flex items-center justify-center bg-slate-100 hover:bg-slate-200 transition duration-150 rounded-full ${dropdownOpen && 'bg-slate-200'}`}
|
||||
aria-haspopup="true"
|
||||
onClick={() => setDropdownOpen(!dropdownOpen)}
|
||||
aria-expanded={dropdownOpen}
|
||||
>
|
||||
<span className="sr-only">Notifications</span>
|
||||
<svg className="w-4 h-4" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
|
||||
<path className="fill-current text-slate-500" d="M6.5 0C2.91 0 0 2.462 0 5.5c0 1.075.37 2.074 1 2.922V12l2.699-1.542A7.454 7.454 0 006.5 11c3.59 0 6.5-2.462 6.5-5.5S10.09 0 6.5 0z" />
|
||||
<path className="fill-current text-slate-400" d="M16 9.5c0-.987-.429-1.897-1.147-2.639C14.124 10.348 10.66 13 6.5 13c-.103 0-.202-.018-.305-.021C7.231 13.617 8.556 14 10 14c.449 0 .886-.04 1.307-.11L15 16v-4h-.012C15.627 11.285 16 10.425 16 9.5z" />
|
||||
</svg>
|
||||
<div className="absolute top-0 right-0 w-2.5 h-2.5 bg-rose-500 border-2 border-white rounded-full"></div>
|
||||
</button>
|
||||
|
||||
<Transition
|
||||
className={`origin-top-right z-10 absolute top-full -mr-48 sm:mr-0 min-w-80 bg-white border border-slate-200 py-1.5 rounded shadow-lg overflow-hidden mt-1 ${align === 'right' ? 'right-0' : 'left-0'}`}
|
||||
show={dropdownOpen}
|
||||
enter="transition ease-out duration-200 transform"
|
||||
enterStart="opacity-0 -translate-y-2"
|
||||
enterEnd="opacity-100 translate-y-0"
|
||||
leave="transition ease-out duration-200"
|
||||
leaveStart="opacity-100"
|
||||
leaveEnd="opacity-0"
|
||||
>
|
||||
<div
|
||||
ref={dropdown}
|
||||
onFocus={() => setDropdownOpen(true)}
|
||||
onBlur={() => setDropdownOpen(false)}
|
||||
>
|
||||
<div className="text-xs font-semibold text-slate-400 uppercase pt-1.5 pb-2 px-4">Notifications</div>
|
||||
<ul>
|
||||
<li className="border-b border-slate-200 last:border-0">
|
||||
<Link
|
||||
className="block py-2 px-4 hover:bg-slate-50"
|
||||
to="#0"
|
||||
onClick={() => setDropdownOpen(!dropdownOpen)}
|
||||
>
|
||||
<span className="block text-sm mb-2">📣 <span className="font-medium text-slate-800">Edit your information in a swipe</span> Sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim.</span>
|
||||
<span className="block text-xs font-medium text-slate-400">Feb 12, 2021</span>
|
||||
</Link>
|
||||
</li>
|
||||
<li className="border-b border-slate-200 last:border-0">
|
||||
<Link
|
||||
className="block py-2 px-4 hover:bg-slate-50"
|
||||
to="#0"
|
||||
onClick={() => setDropdownOpen(!dropdownOpen)}
|
||||
>
|
||||
<span className="block text-sm mb-2">📣 <span className="font-medium text-slate-800">Edit your information in a swipe</span> Sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim.</span>
|
||||
<span className="block text-xs font-medium text-slate-400">Feb 9, 2021</span>
|
||||
</Link>
|
||||
</li>
|
||||
<li className="border-b border-slate-200 last:border-0">
|
||||
<Link
|
||||
className="block py-2 px-4 hover:bg-slate-50"
|
||||
to="#0"
|
||||
onClick={() => setDropdownOpen(!dropdownOpen)}
|
||||
>
|
||||
<span className="block text-sm mb-2">🚀<span className="font-medium text-slate-800">Say goodbye to paper receipts!</span> Sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim.</span>
|
||||
<span className="block text-xs font-medium text-slate-400">Jan 24, 2020</span>
|
||||
</Link>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</Transition>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default DropdownNotifications;
|
||||
@@ -1,13 +1,12 @@
|
||||
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 { store } from '../store/store';
|
||||
import { generateSvgAvatar } from '../images/GenerateOnboardingSvg/GenerateSvg';
|
||||
import UserAvatar from '../images/user-avatar-32.png';
|
||||
|
||||
function DropdownProfile({
|
||||
align
|
||||
}) {
|
||||
|
||||
const DropdownProfile = observer(({ align }) => {
|
||||
const [dropdownOpen, setDropdownOpen] = useState(false);
|
||||
|
||||
const trigger = useRef(null);
|
||||
@@ -17,7 +16,12 @@ function DropdownProfile({
|
||||
useEffect(() => {
|
||||
const clickHandler = ({ target }) => {
|
||||
if (!dropdown.current) return;
|
||||
if (!dropdownOpen || dropdown.current.contains(target) || trigger.current.contains(target)) return;
|
||||
if (
|
||||
!dropdownOpen ||
|
||||
dropdown.current.contains(target) ||
|
||||
trigger.current.contains(target)
|
||||
)
|
||||
return;
|
||||
setDropdownOpen(false);
|
||||
};
|
||||
document.addEventListener('click', clickHandler);
|
||||
@@ -34,6 +38,11 @@ function DropdownProfile({
|
||||
return () => document.removeEventListener('keydown', keyHandler);
|
||||
});
|
||||
|
||||
const logOut = () => {
|
||||
sessionStorage.removeItem('passPhrase');
|
||||
store.fetchPassPhrase();
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="relative inline-flex">
|
||||
<button
|
||||
@@ -43,17 +52,30 @@ 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(store.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">
|
||||
<span className="truncate ml-2 text-sm font-medium group-hover:text-slate-800">
|
||||
{store.accountName}
|
||||
</span>
|
||||
<svg
|
||||
className="w-3 h-3 shrink-0 ml-1 fill-current text-slate-400"
|
||||
viewBox="0 0 12 12"
|
||||
>
|
||||
<path d="M5.9 11.4L.5 6l1.4-1.4 4 4 4-4L11.3 6z" />
|
||||
</svg>
|
||||
</div>
|
||||
</button>
|
||||
|
||||
<Transition
|
||||
className={`origin-top-right z-10 absolute top-full min-w-44 bg-white border border-slate-200 py-1.5 rounded shadow-lg overflow-hidden mt-1 ${align === 'right' ? 'right-0' : 'left-0'}`}
|
||||
className={`origin-top-right z-10 absolute top-full min-w-44 bg-white border border-slate-200 py-1.5 rounded shadow-lg overflow-hidden mt-1 ${
|
||||
align === 'right' ? 'right-0' : 'left-0'
|
||||
}`}
|
||||
show={dropdownOpen}
|
||||
enter="transition ease-out duration-200 transform"
|
||||
enterStart="opacity-0 -translate-y-2"
|
||||
@@ -68,24 +90,24 @@ function DropdownProfile({
|
||||
onBlur={() => setDropdownOpen(false)}
|
||||
>
|
||||
<div className="pt-0.5 pb-2 px-3 mb-1 border-b border-slate-200">
|
||||
<div className="font-medium text-slate-800">Acme Inc.</div>
|
||||
<div className="text-xs text-slate-500 italic">Administrator</div>
|
||||
<div className="font-medium text-slate-800">
|
||||
{store.accountName}
|
||||
</div>
|
||||
</div>
|
||||
<ul>
|
||||
<li>
|
||||
<Link
|
||||
className="font-medium text-sm text-indigo-500 hover:text-indigo-600 flex items-center py-1 px-3"
|
||||
to="/"
|
||||
<span
|
||||
className="cursor-pointer font-medium text-sm text-indigo-500 hover:text-indigo-600 flex items-center py-1 px-3"
|
||||
onClick={() => setDropdownOpen(!dropdownOpen)}
|
||||
>
|
||||
Settings
|
||||
</Link>
|
||||
</span>
|
||||
</li>
|
||||
<li>
|
||||
<Link
|
||||
className="font-medium text-sm text-indigo-500 hover:text-indigo-600 flex items-center py-1 px-3"
|
||||
to="/"
|
||||
onClick={() => setDropdownOpen(!dropdownOpen)}
|
||||
onClick={() => logOut()}
|
||||
>
|
||||
Sign Out
|
||||
</Link>
|
||||
@@ -94,7 +116,7 @@ function DropdownProfile({
|
||||
</div>
|
||||
</Transition>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
export default DropdownProfile;
|
||||
|
||||
104
src/components/DropdownTransaction.jsx
Normal file
@@ -0,0 +1,104 @@
|
||||
import React, { useState, useRef, useEffect } from 'react';
|
||||
import Transition from '../utils/Transition';
|
||||
|
||||
function DropdownTransaction({ align, value, onChange }) {
|
||||
const [dropdownOpen, setDropdownOpen] = useState(false);
|
||||
|
||||
const trigger = useRef(null);
|
||||
const dropdown = useRef(null);
|
||||
|
||||
const changeValue = (val) => {
|
||||
setDropdownOpen(false);
|
||||
onChange(val);
|
||||
};
|
||||
|
||||
// close on click outside
|
||||
useEffect(() => {
|
||||
const clickHandler = ({ target }) => {
|
||||
if (!dropdown.current) return;
|
||||
if (
|
||||
!dropdownOpen ||
|
||||
dropdown.current.contains(target) ||
|
||||
trigger.current.contains(target)
|
||||
)
|
||||
return;
|
||||
setDropdownOpen(false);
|
||||
};
|
||||
document.addEventListener('click', clickHandler);
|
||||
return () => document.removeEventListener('click', clickHandler);
|
||||
});
|
||||
|
||||
// close if the esc key is pressed
|
||||
useEffect(() => {
|
||||
const keyHandler = ({ keyCode }) => {
|
||||
if (!dropdownOpen || keyCode !== 27) return;
|
||||
setDropdownOpen(false);
|
||||
};
|
||||
document.addEventListener('keydown', keyHandler);
|
||||
return () => document.removeEventListener('keydown', keyHandler);
|
||||
});
|
||||
|
||||
return (
|
||||
<div className="relative inline-flex">
|
||||
<button
|
||||
ref={trigger}
|
||||
className="inline-flex justify-center items-center group"
|
||||
aria-haspopup="true"
|
||||
aria-expanded={dropdownOpen}
|
||||
onClick={() => setDropdownOpen(!dropdownOpen)}
|
||||
>
|
||||
<div className="flex items-center truncate">
|
||||
<span className="truncate font-medium text-indigo-500 group-hover:text-indigo-600">
|
||||
{value}
|
||||
</span>
|
||||
<svg
|
||||
className="w-3 h-3 shrink-0 ml-1 fill-current text-slate-400"
|
||||
viewBox="0 0 12 12"
|
||||
>
|
||||
<path d="M5.9 11.4L.5 6l1.4-1.4 4 4 4-4L11.3 6z" />
|
||||
</svg>
|
||||
</div>
|
||||
</button>
|
||||
|
||||
<Transition
|
||||
className={`origin-top-right z-10 absolute top-full min-w-44 bg-white border border-slate-200 py-1.5 rounded shadow-lg overflow-hidden mt-1 ${
|
||||
align === 'right' ? 'right-0' : 'left-0'
|
||||
}`}
|
||||
show={dropdownOpen}
|
||||
enter="transition ease-out duration-200 transform"
|
||||
enterStart="opacity-0 -translate-y-2"
|
||||
enterEnd="opacity-100 translate-y-0"
|
||||
leave="transition ease-out duration-200"
|
||||
leaveStart="opacity-100"
|
||||
leaveEnd="opacity-0"
|
||||
>
|
||||
<div
|
||||
ref={dropdown}
|
||||
onFocus={() => setDropdownOpen(true)}
|
||||
onBlur={() => setDropdownOpen(false)}
|
||||
>
|
||||
<ul>
|
||||
<li>
|
||||
<span
|
||||
className="font-medium text-sm text-slate-600 hover:text-slate-800 flex items-center py-1 px-3 cursor-pointer"
|
||||
onClick={() => changeValue('Voiting')}
|
||||
>
|
||||
Voiting
|
||||
</span>
|
||||
</li>
|
||||
<li>
|
||||
<span
|
||||
className="font-medium text-sm text-slate-600 hover:text-slate-800 flex items-center py-1 px-3 cursor-pointer"
|
||||
onClick={() => changeValue('Unlocking')}
|
||||
>
|
||||
Unlocking
|
||||
</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</Transition>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default DropdownTransaction;
|
||||
31
src/components/Filters.js
Normal file
@@ -0,0 +1,31 @@
|
||||
import React from 'react';
|
||||
|
||||
export const Filters = ({ value, onChange, values = [] }) => {
|
||||
return (
|
||||
<div className="mb-5">
|
||||
<ul className="flex flex-wrap -m-1">
|
||||
{values.map((e) =>
|
||||
e === value ? (
|
||||
<li className="m-1" key={e}>
|
||||
<button
|
||||
className="inline-flex items-center justify-center text-sm font-medium leading-5 rounded-full px-3 py-1 border border-transparent shadow-sm bg-indigo-500 text-white duration-150 ease-in-out"
|
||||
onClick={() => onChange(e)}
|
||||
>
|
||||
{e}
|
||||
</button>
|
||||
</li>
|
||||
) : (
|
||||
<li className="m-1" key={e}>
|
||||
<button
|
||||
className="inline-flex items-center justify-center text-sm font-medium leading-5 rounded-full px-3 py-1 border border-slate-200 hover:border-slate-300 shadow-sm bg-white text-slate-500 duration-150 ease-in-out"
|
||||
onClick={() => onChange(e)}
|
||||
>
|
||||
{e}
|
||||
</button>
|
||||
</li>
|
||||
)
|
||||
)}
|
||||
</ul>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
17
src/components/LoadingOverlay.jsx
Normal file
@@ -0,0 +1,17 @@
|
||||
import ReactDOM from 'react-dom';
|
||||
import React from 'react';
|
||||
import { ThreeCircles } from 'react-loader-spinner';
|
||||
|
||||
export const LoadingOverlay = () =>
|
||||
ReactDOM.createPortal(
|
||||
<div className="absolute left-0 top-0 h-screen w-screen z-50 loading-overlay">
|
||||
<ThreeCircles
|
||||
height="100"
|
||||
width="100"
|
||||
color="#6366f1"
|
||||
visible={true}
|
||||
ariaLabel="three-circles-rotating"
|
||||
/>
|
||||
</div>,
|
||||
document.body
|
||||
);
|
||||
@@ -1,197 +0,0 @@
|
||||
import React, { useRef, useEffect } from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
import Transition from '../utils/Transition';
|
||||
|
||||
function ModalSearch({
|
||||
id,
|
||||
searchId,
|
||||
modalOpen,
|
||||
setModalOpen
|
||||
}) {
|
||||
|
||||
const modalContent = useRef(null);
|
||||
const searchInput = useRef(null);
|
||||
|
||||
// close on click outside
|
||||
useEffect(() => {
|
||||
const clickHandler = ({ target }) => {
|
||||
if (!modalOpen || modalContent.current.contains(target)) return
|
||||
setModalOpen(false);
|
||||
};
|
||||
document.addEventListener('click', clickHandler);
|
||||
return () => document.removeEventListener('click', clickHandler);
|
||||
});
|
||||
|
||||
// close if the esc key is pressed
|
||||
useEffect(() => {
|
||||
const keyHandler = ({ keyCode }) => {
|
||||
if (!modalOpen || keyCode !== 27) return;
|
||||
setModalOpen(false);
|
||||
};
|
||||
document.addEventListener('keydown', keyHandler);
|
||||
return () => document.removeEventListener('keydown', keyHandler);
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
modalOpen && searchInput.current.focus();
|
||||
}, [modalOpen]);
|
||||
|
||||
return (
|
||||
<>
|
||||
{/* Modal backdrop */}
|
||||
<Transition
|
||||
className="fixed inset-0 bg-slate-900 bg-opacity-30 z-50 transition-opacity"
|
||||
show={modalOpen}
|
||||
enter="transition ease-out duration-200"
|
||||
enterStart="opacity-0"
|
||||
enterEnd="opacity-100"
|
||||
leave="transition ease-out duration-100"
|
||||
leaveStart="opacity-100"
|
||||
leaveEnd="opacity-0"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
{/* Modal dialog */}
|
||||
<Transition
|
||||
id={id}
|
||||
className="fixed inset-0 z-50 overflow-hidden flex items-start top-20 mb-4 justify-center transform px-4 sm:px-6"
|
||||
role="dialog"
|
||||
aria-modal="true"
|
||||
show={modalOpen}
|
||||
enter="transition ease-in-out duration-200"
|
||||
enterStart="opacity-0 translate-y-4"
|
||||
enterEnd="opacity-100 translate-y-0"
|
||||
leave="transition ease-in-out duration-200"
|
||||
leaveStart="opacity-100 translate-y-0"
|
||||
leaveEnd="opacity-0 translate-y-4"
|
||||
>
|
||||
<div ref={modalContent} className="bg-white overflow-auto max-w-2xl w-full max-h-full rounded shadow-lg">
|
||||
{/* Search form */}
|
||||
<form className="border-b border-slate-200">
|
||||
<div className="relative">
|
||||
<label htmlFor={searchId} className="sr-only">Search</label>
|
||||
<input id={searchId} className="w-full border-0 focus:ring-transparent placeholder-slate-400 appearance-none py-3 pl-10 pr-4" type="search" placeholder="Search Anything…" ref={searchInput} />
|
||||
<button className="absolute inset-0 right-auto group" type="submit" aria-label="Search">
|
||||
<svg className="w-4 h-4 shrink-0 fill-current text-slate-400 group-hover:text-slate-500 ml-4 mr-2" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M7 14c-3.86 0-7-3.14-7-7s3.14-7 7-7 7 3.14 7 7-3.14 7-7 7zM7 2C4.243 2 2 4.243 2 7s2.243 5 5 5 5-2.243 5-5-2.243-5-5-5z" />
|
||||
<path d="M15.707 14.293L13.314 11.9a8.019 8.019 0 01-1.414 1.414l2.393 2.393a.997.997 0 001.414 0 .999.999 0 000-1.414z" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
<div className="py-4 px-2">
|
||||
{/* Recent searches */}
|
||||
<div className="mb-3 last:mb-0">
|
||||
<div className="text-xs font-semibold text-slate-400 uppercase px-2 mb-2">Recent searches</div>
|
||||
<ul className="text-sm">
|
||||
<li>
|
||||
<Link
|
||||
className="flex items-center p-2 text-slate-800 hover:text-white hover:bg-indigo-500 rounded group"
|
||||
to="#0"
|
||||
onClick={() => setModalOpen(!modalOpen)}
|
||||
>
|
||||
<svg className="w-4 h-4 fill-current text-slate-400 group-hover:text-white group-hover:text-opacity-50 shrink-0 mr-3" viewBox="0 0 16 16">
|
||||
<path d="M15.707 14.293v.001a1 1 0 01-1.414 1.414L11.185 12.6A6.935 6.935 0 017 14a7.016 7.016 0 01-5.173-2.308l-1.537 1.3L0 8l4.873 1.12-1.521 1.285a4.971 4.971 0 008.59-2.835l1.979.454a6.971 6.971 0 01-1.321 3.157l3.107 3.112zM14 6L9.127 4.88l1.521-1.28a4.971 4.971 0 00-8.59 2.83L.084 5.976a6.977 6.977 0 0112.089-3.668l1.537-1.3L14 6z" />
|
||||
</svg>
|
||||
<span>Form Builder - 23 hours on-demand video</span>
|
||||
</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Link
|
||||
className="flex items-center p-2 text-slate-800 hover:text-white hover:bg-indigo-500 rounded group"
|
||||
to="#0"
|
||||
onClick={() => setModalOpen(!modalOpen)}
|
||||
>
|
||||
<svg className="w-4 h-4 fill-current text-slate-400 group-hover:text-white group-hover:text-opacity-50 shrink-0 mr-3" viewBox="0 0 16 16">
|
||||
<path d="M15.707 14.293v.001a1 1 0 01-1.414 1.414L11.185 12.6A6.935 6.935 0 017 14a7.016 7.016 0 01-5.173-2.308l-1.537 1.3L0 8l4.873 1.12-1.521 1.285a4.971 4.971 0 008.59-2.835l1.979.454a6.971 6.971 0 01-1.321 3.157l3.107 3.112zM14 6L9.127 4.88l1.521-1.28a4.971 4.971 0 00-8.59 2.83L.084 5.976a6.977 6.977 0 0112.089-3.668l1.537-1.3L14 6z" />
|
||||
</svg>
|
||||
<span>Access Mosaic on mobile and TV</span>
|
||||
</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Link
|
||||
className="flex items-center p-2 text-slate-800 hover:text-white hover:bg-indigo-500 rounded group"
|
||||
to="#0"
|
||||
onClick={() => setModalOpen(!modalOpen)}
|
||||
>
|
||||
<svg className="w-4 h-4 fill-current text-slate-400 group-hover:text-white group-hover:text-opacity-50 shrink-0 mr-3" viewBox="0 0 16 16">
|
||||
<path d="M15.707 14.293v.001a1 1 0 01-1.414 1.414L11.185 12.6A6.935 6.935 0 017 14a7.016 7.016 0 01-5.173-2.308l-1.537 1.3L0 8l4.873 1.12-1.521 1.285a4.971 4.971 0 008.59-2.835l1.979.454a6.971 6.971 0 01-1.321 3.157l3.107 3.112zM14 6L9.127 4.88l1.521-1.28a4.971 4.971 0 00-8.59 2.83L.084 5.976a6.977 6.977 0 0112.089-3.668l1.537-1.3L14 6z" />
|
||||
</svg>
|
||||
<span>Product Update - Q4 2021</span>
|
||||
</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Link
|
||||
className="flex items-center p-2 text-slate-800 hover:text-white hover:bg-indigo-500 rounded group"
|
||||
to="#0"
|
||||
onClick={() => setModalOpen(!modalOpen)}
|
||||
>
|
||||
<svg className="w-4 h-4 fill-current text-slate-400 group-hover:text-white group-hover:text-opacity-50 shrink-0 mr-3" viewBox="0 0 16 16">
|
||||
<path d="M15.707 14.293v.001a1 1 0 01-1.414 1.414L11.185 12.6A6.935 6.935 0 017 14a7.016 7.016 0 01-5.173-2.308l-1.537 1.3L0 8l4.873 1.12-1.521 1.285a4.971 4.971 0 008.59-2.835l1.979.454a6.971 6.971 0 01-1.321 3.157l3.107 3.112zM14 6L9.127 4.88l1.521-1.28a4.971 4.971 0 00-8.59 2.83L.084 5.976a6.977 6.977 0 0112.089-3.668l1.537-1.3L14 6z" />
|
||||
</svg>
|
||||
<span>Master Digital Marketing Strategy course</span>
|
||||
</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Link
|
||||
className="flex items-center p-2 text-slate-800 hover:text-white hover:bg-indigo-500 rounded group"
|
||||
to="#0"
|
||||
onClick={() => setModalOpen(!modalOpen)}
|
||||
>
|
||||
<svg className="w-4 h-4 fill-current text-slate-400 group-hover:text-white group-hover:text-opacity-50 shrink-0 mr-3" viewBox="0 0 16 16">
|
||||
<path d="M15.707 14.293v.001a1 1 0 01-1.414 1.414L11.185 12.6A6.935 6.935 0 017 14a7.016 7.016 0 01-5.173-2.308l-1.537 1.3L0 8l4.873 1.12-1.521 1.285a4.971 4.971 0 008.59-2.835l1.979.454a6.971 6.971 0 01-1.321 3.157l3.107 3.112zM14 6L9.127 4.88l1.521-1.28a4.971 4.971 0 00-8.59 2.83L.084 5.976a6.977 6.977 0 0112.089-3.668l1.537-1.3L14 6z" />
|
||||
</svg>
|
||||
<span>Dedicated forms for products</span>
|
||||
</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Link
|
||||
className="flex items-center p-2 text-slate-800 hover:text-white hover:bg-indigo-500 rounded group"
|
||||
to="#0"
|
||||
onClick={() => setModalOpen(!modalOpen)}
|
||||
>
|
||||
<svg className="w-4 h-4 fill-current text-slate-400 group-hover:text-white group-hover:text-opacity-50 shrink-0 mr-3" viewBox="0 0 16 16">
|
||||
<path d="M15.707 14.293v.001a1 1 0 01-1.414 1.414L11.185 12.6A6.935 6.935 0 017 14a7.016 7.016 0 01-5.173-2.308l-1.537 1.3L0 8l4.873 1.12-1.521 1.285a4.971 4.971 0 008.59-2.835l1.979.454a6.971 6.971 0 01-1.321 3.157l3.107 3.112zM14 6L9.127 4.88l1.521-1.28a4.971 4.971 0 00-8.59 2.83L.084 5.976a6.977 6.977 0 0112.089-3.668l1.537-1.3L14 6z" />
|
||||
</svg>
|
||||
<span>Product Update - Q4 2021</span>
|
||||
</Link>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
{/* Recent pages */}
|
||||
<div className="mb-3 last:mb-0">
|
||||
<div className="text-xs font-semibold text-slate-400 uppercase px-2 mb-2">Recent pages</div>
|
||||
<ul className="text-sm">
|
||||
<li>
|
||||
<Link
|
||||
className="flex items-center p-2 text-slate-800 hover:text-white hover:bg-indigo-500 rounded group"
|
||||
to="#0"
|
||||
onClick={() => setModalOpen(!modalOpen)}
|
||||
>
|
||||
<svg className="w-4 h-4 fill-current text-slate-400 group-hover:text-white group-hover:text-opacity-50 shrink-0 mr-3" viewBox="0 0 16 16">
|
||||
<path d="M14 0H2c-.6 0-1 .4-1 1v14c0 .6.4 1 1 1h8l5-5V1c0-.6-.4-1-1-1zM3 2h10v8H9v4H3V2z" />
|
||||
</svg>
|
||||
<span><span className="font-medium text-slate-800 group-hover:text-white">Messages</span> - Conversation / … / Mike Mills</span>
|
||||
</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Link
|
||||
className="flex items-center p-2 text-slate-800 hover:text-white hover:bg-indigo-500 rounded group"
|
||||
to="#0"
|
||||
onClick={() => setModalOpen(!modalOpen)}
|
||||
>
|
||||
<svg className="w-4 h-4 fill-current text-slate-400 group-hover:text-white group-hover:text-opacity-50 shrink-0 mr-3" viewBox="0 0 16 16">
|
||||
<path d="M14 0H2c-.6 0-1 .4-1 1v14c0 .6.4 1 1 1h8l5-5V1c0-.6-.4-1-1-1zM3 2h10v8H9v4H3V2z" />
|
||||
</svg>
|
||||
<span><span className="font-medium text-slate-800 group-hover:text-white">Messages</span> - Conversation / … / Eva Patrick</span>
|
||||
</Link>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Transition>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default ModalSearch;
|
||||
14
src/components/NotificationContainer.jsx
Normal file
@@ -0,0 +1,14 @@
|
||||
import React from 'react';
|
||||
import { observer } from 'mobx-react-lite';
|
||||
import { Toast } from './Toast2';
|
||||
import { store } from '../store/store';
|
||||
|
||||
export const NotificationContainer = observer(() => (
|
||||
<div className="absolute z-50 top-2 right-2 gap-2">
|
||||
{store.notifications.map((e) => (
|
||||
<Toast type={e.type} key={e.id} id={e.id}>
|
||||
{e.message}
|
||||
</Toast>
|
||||
))}
|
||||
</div>
|
||||
));
|
||||
52
src/components/PaginationClassic.jsx
Normal file
@@ -0,0 +1,52 @@
|
||||
import React from 'react';
|
||||
import cn from 'classnames';
|
||||
|
||||
function PaginationClassic({ count, limit, offset, onNextPage, onPrevPage }) {
|
||||
return (
|
||||
<div className="flex flex-col sm:flex-row sm:items-center sm:justify-between">
|
||||
<nav
|
||||
className="mb-4 sm:mb-0 sm:order-1"
|
||||
role="navigation"
|
||||
aria-label="Navigation"
|
||||
>
|
||||
<ul className="flex justify-center">
|
||||
<li className="ml-3 first:ml-0">
|
||||
<button
|
||||
className={cn(
|
||||
'btn bg-white border-slate-200 text-indigo-500',
|
||||
{ 'cursor-not-allowed text-slate-300': offset === 0 },
|
||||
{ 'hover:border-slate-300': offset !== 0 }
|
||||
)}
|
||||
disabled={offset === 0}
|
||||
onClick={onPrevPage}
|
||||
>
|
||||
<- Previous
|
||||
</button>
|
||||
</li>
|
||||
<li className="ml-3 first:ml-0">
|
||||
<button
|
||||
className={cn(
|
||||
'btn bg-white border-slate-200 text-indigo-500',
|
||||
{
|
||||
'cursor-not-allowed text-slate-300': offset + limit >= count,
|
||||
},
|
||||
{ 'hover:border-slate-300': offset + limit < count }
|
||||
)}
|
||||
disabled={offset + limit >= count}
|
||||
onClick={onNextPage}
|
||||
>
|
||||
Next ->
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
<div className="text-sm text-slate-500 text-center sm:text-left">
|
||||
Showing <span className="font-medium text-slate-600">{offset + 1}</span>{' '}
|
||||
to <span className="font-medium text-slate-600">{offset + limit}</span>{' '}
|
||||
of <span className="font-medium text-slate-600">{count}</span> results
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default PaginationClassic;
|
||||
90
src/components/Toast2.jsx
Normal file
@@ -0,0 +1,90 @@
|
||||
import React, { useEffect } from 'react';
|
||||
import { store } from '../store/store';
|
||||
import { observer } from 'mobx-react-lite';
|
||||
|
||||
export const Toast = observer(({ children, className, type, id }) => {
|
||||
const typeIcon = (type) => {
|
||||
switch (type) {
|
||||
case 'warning':
|
||||
return (
|
||||
<svg
|
||||
className="w-4 h-4 shrink-0 fill-current opacity-80 mt-[3px] mr-3"
|
||||
viewBox="0 0 16 16"
|
||||
>
|
||||
<path d="M8 0C3.6 0 0 3.6 0 8s3.6 8 8 8 8-3.6 8-8-3.6-8-8-8zm0 12c-.6 0-1-.4-1-1s.4-1 1-1 1 .4 1 1-.4 1-1 1zm1-3H7V4h2v5z" />
|
||||
</svg>
|
||||
);
|
||||
case 'error':
|
||||
return (
|
||||
<svg
|
||||
className="w-4 h-4 shrink-0 fill-current opacity-80 mt-[3px] mr-3"
|
||||
viewBox="0 0 16 16"
|
||||
>
|
||||
<path d="M8 0C3.6 0 0 3.6 0 8s3.6 8 8 8 8-3.6 8-8-3.6-8-8-8zm3.5 10.1l-1.4 1.4L8 9.4l-2.1 2.1-1.4-1.4L6.6 8 4.5 5.9l1.4-1.4L8 6.6l2.1-2.1 1.4 1.4L9.4 8l2.1 2.1z" />
|
||||
</svg>
|
||||
);
|
||||
case 'success':
|
||||
return (
|
||||
<svg
|
||||
className="w-4 h-4 shrink-0 fill-current opacity-80 mt-[3px] mr-3"
|
||||
viewBox="0 0 16 16"
|
||||
>
|
||||
<path d="M8 0C3.6 0 0 3.6 0 8s3.6 8 8 8 8-3.6 8-8-3.6-8-8-8zM7 11.4L3.6 8 5 6.6l2 2 4-4L12.4 6 7 11.4z" />
|
||||
</svg>
|
||||
);
|
||||
default:
|
||||
return (
|
||||
<svg
|
||||
className="w-4 h-4 shrink-0 fill-current opacity-80 mt-[3px] mr-3"
|
||||
viewBox="0 0 16 16"
|
||||
>
|
||||
<path d="M8 0C3.6 0 0 3.6 0 8s3.6 8 8 8 8-3.6 8-8-3.6-8-8-8zm1 12H7V7h2v5zM8 6c-.6 0-1-.4-1-1s.4-1 1-1 1 .4 1 1-.4 1-1 1z" />
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
const typeColor = (type) => {
|
||||
switch (type) {
|
||||
case 'warning':
|
||||
return 'bg-amber-100 border-amber-200 text-amber-600';
|
||||
case 'error':
|
||||
return 'bg-rose-100 border-rose-200 text-rose-600';
|
||||
case 'success':
|
||||
return 'bg-emerald-100 border-emerald-200 text-emerald-600';
|
||||
default:
|
||||
return 'bg-indigo-100 border-indigo-200 text-indigo-500';
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const timerId = setTimeout(() => store.removeNotification(id), 3000);
|
||||
return () => clearTimeout(timerId);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className={className}>
|
||||
<div
|
||||
className={`inline-flex min-w-80 px-4 py-2 rounded-sm text-sm border ${typeColor(
|
||||
type
|
||||
)}`}
|
||||
>
|
||||
<div className="flex w-full justify-between items-start">
|
||||
<div className="flex">
|
||||
{typeIcon(type)}
|
||||
<div>{children}</div>
|
||||
</div>
|
||||
<button
|
||||
className="opacity-70 hover:opacity-80 ml-3 mt-[3px]"
|
||||
onClick={() => store.removeNotification(id)}
|
||||
>
|
||||
<div className="sr-only">Close</div>
|
||||
<svg className="w-4 h-4 fill-current">
|
||||
<path d="M7.95 6.536l4.242-4.243a1 1 0 111.415 1.414L9.364 7.95l4.243 4.242a1 1 0 11-1.415 1.415L7.95 9.364l-4.243 4.243a1 1 0 01-1.414-1.415L6.536 7.95 2.293 3.707a1 1 0 011.414-1.414L7.95 6.536z" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
@@ -1,90 +0,0 @@
|
||||
import React, { useState } from 'react';
|
||||
import Transition from '../utils/Transition';
|
||||
|
||||
function Tooltip({
|
||||
children,
|
||||
className,
|
||||
bg,
|
||||
size,
|
||||
position,
|
||||
}) {
|
||||
|
||||
const [tooltipOpen, setTooltipOpen] = useState(false);
|
||||
|
||||
const positionOuterClasses = (position) => {
|
||||
switch (position) {
|
||||
case 'right':
|
||||
return 'left-full top-1/2 transform -translate-y-1/2';
|
||||
case 'left':
|
||||
return 'right-full top-1/2 transform -translate-y-1/2';
|
||||
case 'bottom':
|
||||
return 'top-full left-1/2 transform -translate-x-1/2';
|
||||
default:
|
||||
return 'bottom-full left-1/2 transform -translate-x-1/2';
|
||||
}
|
||||
}
|
||||
|
||||
const sizeClasses = (size) => {
|
||||
switch (size) {
|
||||
case 'lg':
|
||||
return 'min-w-72 p-3';
|
||||
case 'md':
|
||||
return 'min-w-56 p-3';
|
||||
case 'sm':
|
||||
return 'min-w-44 p-2';
|
||||
default:
|
||||
return 'p-2';
|
||||
}
|
||||
};
|
||||
|
||||
const positionInnerClasses = (position) => {
|
||||
switch (position) {
|
||||
case 'right':
|
||||
return 'ml-2';
|
||||
case 'left':
|
||||
return 'mr-2';
|
||||
case 'bottom':
|
||||
return 'mt-2';
|
||||
default:
|
||||
return 'mb-2';
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`relative ${className}`}
|
||||
onMouseEnter={() => setTooltipOpen(true)}
|
||||
onMouseLeave={() => setTooltipOpen(false)}
|
||||
onFocus={() => setTooltipOpen(true)}
|
||||
onBlur={() => setTooltipOpen(false)}
|
||||
>
|
||||
<button
|
||||
className="block"
|
||||
aria-haspopup="true"
|
||||
aria-expanded={tooltipOpen}
|
||||
onClick={(e) => e.preventDefault()}
|
||||
>
|
||||
<svg className="w-4 h-4 fill-current text-slate-400" viewBox="0 0 16 16">
|
||||
<path d="M8 0C3.6 0 0 3.6 0 8s3.6 8 8 8 8-3.6 8-8-3.6-8-8-8zm0 12c-.6 0-1-.4-1-1s.4-1 1-1 1 .4 1 1-.4 1-1 1zm1-3H7V4h2v5z" />
|
||||
</svg>
|
||||
</button>
|
||||
<div className={`z-10 absolute ${positionOuterClasses(position)}`}>
|
||||
<Transition
|
||||
show={tooltipOpen}
|
||||
tag="div"
|
||||
className={`rounded overflow-hidden ${bg === 'dark' ? 'bg-slate-800' : 'bg-white border border-slate-200 shadow-lg'} ${sizeClasses(size)} ${positionInnerClasses(position)}`}
|
||||
enter="transition ease-out duration-200 transform"
|
||||
enterStart="opacity-0 -translate-y-2"
|
||||
enterEnd="opacity-100 translate-y-0"
|
||||
leave="transition ease-out duration-200"
|
||||
leaveStart="opacity-100"
|
||||
leaveEnd="opacity-0"
|
||||
>
|
||||
{children}
|
||||
</Transition>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default Tooltip;
|
||||
@@ -4,7 +4,7 @@
|
||||
// Customise flatpickr
|
||||
$calendarPadding: 24px;
|
||||
$daySize: 36px;
|
||||
$daysWidth: $daySize*7;
|
||||
$daysWidth: $daySize * 7;
|
||||
|
||||
@keyframes fpFadeInDown {
|
||||
from {
|
||||
@@ -18,59 +18,59 @@ $daysWidth: $daySize*7;
|
||||
}
|
||||
|
||||
.flatpickr-calendar {
|
||||
border: inherit;
|
||||
@apply rounded shadow-lg border border-slate-200 left-1/2;
|
||||
margin-left: - ($daysWidth + $calendarPadding*2)*0.5;
|
||||
padding: $calendarPadding;
|
||||
width: $daysWidth + $calendarPadding*2;
|
||||
border: inherit;
|
||||
@apply rounded shadow-lg border border-slate-200 left-1/2;
|
||||
margin-left: -($daysWidth + $calendarPadding * 2) * 0.5;
|
||||
padding: $calendarPadding;
|
||||
width: $daysWidth + $calendarPadding * 2;
|
||||
}
|
||||
|
||||
@screen lg {
|
||||
.flatpickr-calendar {
|
||||
@apply left-0 right-auto;
|
||||
margin-left: 0;
|
||||
}
|
||||
.flatpickr-calendar {
|
||||
@apply left-0 right-auto;
|
||||
margin-left: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.flatpickr-right.flatpickr-calendar {
|
||||
@apply right-0 left-auto;
|
||||
margin-left: 0;
|
||||
@apply right-0 left-auto;
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
.flatpickr-calendar.animate.open {
|
||||
animation: fpFadeInDown 200ms ease-out;
|
||||
animation: fpFadeInDown 200ms ease-out;
|
||||
}
|
||||
|
||||
.flatpickr-calendar.static {
|
||||
position: absolute;
|
||||
top: calc(100% + 4px);
|
||||
position: absolute;
|
||||
top: calc(100% + 4px);
|
||||
}
|
||||
|
||||
.flatpickr-calendar.static.open {
|
||||
z-index: 20;
|
||||
z-index: 20;
|
||||
}
|
||||
|
||||
.flatpickr-days {
|
||||
width: $daysWidth;
|
||||
width: $daysWidth;
|
||||
}
|
||||
|
||||
.dayContainer {
|
||||
width: $daysWidth;
|
||||
min-width: $daysWidth;
|
||||
max-width: $daysWidth;
|
||||
width: $daysWidth;
|
||||
min-width: $daysWidth;
|
||||
max-width: $daysWidth;
|
||||
}
|
||||
|
||||
.flatpickr-day {
|
||||
@apply bg-slate-50 text-sm font-medium text-slate-600;
|
||||
max-width: $daySize;
|
||||
height: $daySize;
|
||||
line-height: $daySize;
|
||||
@apply bg-slate-50 text-sm font-medium text-slate-600;
|
||||
max-width: $daySize;
|
||||
height: $daySize;
|
||||
line-height: $daySize;
|
||||
}
|
||||
|
||||
.flatpickr-day,
|
||||
.flatpickr-day.prevMonthDay,
|
||||
.flatpickr-day.nextMonthDay {
|
||||
border: none;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.flatpickr-day,
|
||||
@@ -85,7 +85,7 @@ $daysWidth: $daySize*7;
|
||||
.flatpickr-day.selected.startRange.endRange,
|
||||
.flatpickr-day.startRange.startRange.endRange,
|
||||
.flatpickr-day.endRange.startRange.endRange {
|
||||
border-radius: 0;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
.flatpickr-day.flatpickr-disabled,
|
||||
@@ -95,11 +95,11 @@ $daysWidth: $daySize*7;
|
||||
.flatpickr-day.notAllowed,
|
||||
.flatpickr-day.notAllowed.prevMonthDay,
|
||||
.flatpickr-day.notAllowed.nextMonthDay {
|
||||
@apply text-slate-400;
|
||||
@apply text-slate-400;
|
||||
}
|
||||
|
||||
.rangeMode .flatpickr-day {
|
||||
margin: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.flatpickr-day.selected,
|
||||
@@ -120,7 +120,7 @@ $daysWidth: $daySize*7;
|
||||
.flatpickr-day.selected.nextMonthDay,
|
||||
.flatpickr-day.startRange.nextMonthDay,
|
||||
.flatpickr-day.endRange.nextMonthDay {
|
||||
@apply bg-indigo-500 text-indigo-50;
|
||||
@apply bg-indigo-500 text-indigo-50;
|
||||
}
|
||||
|
||||
.flatpickr-day.inRange,
|
||||
@@ -137,92 +137,92 @@ $daysWidth: $daySize*7;
|
||||
.flatpickr-day.nextMonthDay:focus,
|
||||
.flatpickr-day.today:hover,
|
||||
.flatpickr-day.today:focus {
|
||||
@apply bg-indigo-400 text-indigo-50;
|
||||
@apply bg-indigo-400 text-indigo-50;
|
||||
}
|
||||
|
||||
.flatpickr-day.inRange,
|
||||
.flatpickr-day.selected.startRange + .endRange:not(:nth-child(7n+1)),
|
||||
.flatpickr-day.startRange.startRange + .endRange:not(:nth-child(7n+1)),
|
||||
.flatpickr-day.endRange.startRange + .endRange:not(:nth-child(7n+1)) {
|
||||
box-shadow: none;
|
||||
.flatpickr-day.selected.startRange + .endRange:not(:nth-child(7n + 1)),
|
||||
.flatpickr-day.startRange.startRange + .endRange:not(:nth-child(7n + 1)),
|
||||
.flatpickr-day.endRange.startRange + .endRange:not(:nth-child(7n + 1)) {
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.flatpickr-months {
|
||||
align-items: center;
|
||||
margin-top: -8px;
|
||||
margin-bottom: 6px;
|
||||
align-items: center;
|
||||
margin-top: -8px;
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
|
||||
.flatpickr-months .flatpickr-prev-month,
|
||||
.flatpickr-months .flatpickr-next-month {
|
||||
position: static;
|
||||
height: auto;
|
||||
@apply text-slate-600;
|
||||
position: static;
|
||||
height: auto;
|
||||
@apply text-slate-600;
|
||||
}
|
||||
|
||||
.flatpickr-months .flatpickr-prev-month svg,
|
||||
.flatpickr-months .flatpickr-next-month svg {
|
||||
width: 7px;
|
||||
height: 11px;
|
||||
width: 7px;
|
||||
height: 11px;
|
||||
}
|
||||
|
||||
.flatpickr-months .flatpickr-prev-month:hover,
|
||||
.flatpickr-months .flatpickr-next-month:hover,
|
||||
.flatpickr-months .flatpickr-prev-month:hover svg,
|
||||
.flatpickr-months .flatpickr-next-month:hover svg {
|
||||
fill: inherit;
|
||||
@apply text-slate-400;
|
||||
fill: inherit;
|
||||
@apply text-slate-400;
|
||||
}
|
||||
|
||||
.flatpickr-months .flatpickr-prev-month {
|
||||
margin-left: -10px;
|
||||
margin-left: -10px;
|
||||
}
|
||||
|
||||
.flatpickr-months .flatpickr-next-month {
|
||||
margin-right: -10px;
|
||||
margin-right: -10px;
|
||||
}
|
||||
|
||||
.flatpickr-months .flatpickr-month {
|
||||
@apply text-slate-800;
|
||||
height: auto;
|
||||
line-height: inherit;
|
||||
@apply text-slate-800;
|
||||
height: auto;
|
||||
line-height: inherit;
|
||||
}
|
||||
|
||||
.flatpickr-current-month {
|
||||
@apply text-sm font-medium;
|
||||
position: static;
|
||||
height: auto;
|
||||
width: auto;
|
||||
left: auto;
|
||||
padding: 0;
|
||||
@apply text-sm font-medium;
|
||||
position: static;
|
||||
height: auto;
|
||||
width: auto;
|
||||
left: auto;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.flatpickr-current-month span.cur-month {
|
||||
@apply font-medium m-0;
|
||||
@apply font-medium m-0;
|
||||
}
|
||||
|
||||
.flatpickr-current-month span.cur-month:hover {
|
||||
background: none;
|
||||
background: none;
|
||||
}
|
||||
|
||||
.flatpickr-current-month input.cur-year {
|
||||
font-weight: inherit;
|
||||
box-shadow: none !important;
|
||||
font-weight: inherit;
|
||||
box-shadow: none !important;
|
||||
}
|
||||
|
||||
.numInputWrapper:hover {
|
||||
background: none;
|
||||
background: none;
|
||||
}
|
||||
|
||||
.numInputWrapper span {
|
||||
display: none;
|
||||
display: none;
|
||||
}
|
||||
|
||||
span.flatpickr-weekday {
|
||||
@apply text-slate-400 font-medium text-xs;
|
||||
@apply text-slate-400 font-medium text-xs;
|
||||
}
|
||||
|
||||
.flatpickr-calendar.arrowTop::before,
|
||||
.flatpickr-calendar.arrowTop::after {
|
||||
display: none;
|
||||
display: none;
|
||||
}
|
||||
@@ -1,55 +1,55 @@
|
||||
// Range slider
|
||||
$range-thumb-size: 36px;
|
||||
|
||||
input[type=range] {
|
||||
input[type='range'] {
|
||||
appearance: none;
|
||||
background: #ccc;
|
||||
border-radius: 3px;
|
||||
height: 6px;
|
||||
margin-top: ($range-thumb-size - 6px) * 0.5;
|
||||
margin-bottom: ($range-thumb-size - 6px) * 0.5;
|
||||
--thumb-size: #{$range-thumb-size};
|
||||
|
||||
&::-webkit-slider-thumb {
|
||||
appearance: none;
|
||||
background: #ccc;
|
||||
border-radius: 3px;
|
||||
height: 6px;
|
||||
margin-top: ($range-thumb-size - 6px) * 0.5;
|
||||
margin-bottom: ($range-thumb-size - 6px) * 0.5;
|
||||
--thumb-size: #{$range-thumb-size};
|
||||
-webkit-appearance: none;
|
||||
background-color: #000;
|
||||
background-image: url("data:image/svg+xml,%3Csvg width='12' height='8' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M8 .5v7L12 4zM0 4l4 3.5v-7z' fill='%23FFF' fill-rule='nonzero'/%3E%3C/svg%3E");
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
border: 0;
|
||||
border-radius: 50%;
|
||||
cursor: pointer;
|
||||
height: $range-thumb-size;
|
||||
width: $range-thumb-size;
|
||||
}
|
||||
|
||||
&::-webkit-slider-thumb {
|
||||
appearance: none;
|
||||
-webkit-appearance: none;
|
||||
background-color: #000;
|
||||
background-image: url("data:image/svg+xml,%3Csvg width='12' height='8' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M8 .5v7L12 4zM0 4l4 3.5v-7z' fill='%23FFF' fill-rule='nonzero'/%3E%3C/svg%3E");
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
border: 0;
|
||||
border-radius: 50%;
|
||||
cursor: pointer;
|
||||
height: $range-thumb-size;
|
||||
width: $range-thumb-size;
|
||||
}
|
||||
&::-moz-range-thumb {
|
||||
background-color: #000;
|
||||
background-image: url("data:image/svg+xml,%3Csvg width='12' height='8' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M8 .5v7L12 4zM0 4l4 3.5v-7z' fill='%23FFF' fill-rule='nonzero'/%3E%3C/svg%3E");
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
border: 0;
|
||||
border: none;
|
||||
border-radius: 50%;
|
||||
cursor: pointer;
|
||||
height: $range-thumb-size;
|
||||
width: $range-thumb-size;
|
||||
}
|
||||
|
||||
&::-moz-range-thumb {
|
||||
background-color: #000;
|
||||
background-image: url("data:image/svg+xml,%3Csvg width='12' height='8' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M8 .5v7L12 4zM0 4l4 3.5v-7z' fill='%23FFF' fill-rule='nonzero'/%3E%3C/svg%3E");
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
border: 0;
|
||||
border: none;
|
||||
border-radius: 50%;
|
||||
cursor: pointer;
|
||||
height: $range-thumb-size;
|
||||
width: $range-thumb-size;
|
||||
}
|
||||
&::-ms-thumb {
|
||||
background-color: #000;
|
||||
background-image: url("data:image/svg+xml,%3Csvg width='12' height='8' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M8 .5v7L12 4zM0 4l4 3.5v-7z' fill='%23FFF' fill-rule='nonzero'/%3E%3C/svg%3E");
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
border: 0;
|
||||
border-radius: 50%;
|
||||
cursor: pointer;
|
||||
height: $range-thumb-size;
|
||||
width: $range-thumb-size;
|
||||
}
|
||||
|
||||
&::-ms-thumb {
|
||||
background-color: #000;
|
||||
background-image: url("data:image/svg+xml,%3Csvg width='12' height='8' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M8 .5v7L12 4zM0 4l4 3.5v-7z' fill='%23FFF' fill-rule='nonzero'/%3E%3C/svg%3E");
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
border: 0;
|
||||
border-radius: 50%;
|
||||
cursor: pointer;
|
||||
height: $range-thumb-size;
|
||||
width: $range-thumb-size;
|
||||
}
|
||||
|
||||
&::-moz-focus-outer {
|
||||
border: 0;
|
||||
}
|
||||
&::-moz-focus-outer {
|
||||
border: 0;
|
||||
}
|
||||
}
|
||||
@@ -4,8 +4,14 @@
|
||||
.form-select,
|
||||
.form-checkbox,
|
||||
.form-radio {
|
||||
|
||||
&:focus {
|
||||
@apply ring-0;
|
||||
}
|
||||
&:focus {
|
||||
@apply ring-0;
|
||||
}
|
||||
}
|
||||
|
||||
.loading-overlay {
|
||||
background-color: rgba(0, 0, 0, 0.25);
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
@@ -1,44 +1,41 @@
|
||||
// Switch element
|
||||
.form-switch {
|
||||
@apply relative select-none;
|
||||
width: 44px;
|
||||
@apply relative select-none;
|
||||
width: 44px;
|
||||
|
||||
label {
|
||||
@apply block overflow-hidden cursor-pointer h-6 rounded-full;
|
||||
label {
|
||||
@apply block overflow-hidden cursor-pointer h-6 rounded-full;
|
||||
|
||||
> span:first-child {
|
||||
@apply absolute block rounded-full;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
top: 2px;
|
||||
left: 2px;
|
||||
right: 50%;
|
||||
transition: all 0.15s ease-out;
|
||||
}
|
||||
}
|
||||
|
||||
input[type='checkbox'] {
|
||||
&:checked {
|
||||
+ label {
|
||||
@apply bg-indigo-500;
|
||||
|
||||
> span:first-child {
|
||||
@apply absolute block rounded-full;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
top: 2px;
|
||||
left: 2px;
|
||||
right: 50%;
|
||||
transition: all .15s ease-out;
|
||||
left: 22px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
input[type="checkbox"] {
|
||||
&:disabled {
|
||||
+ label {
|
||||
@apply cursor-not-allowed bg-slate-100 border border-slate-200;
|
||||
|
||||
&:checked {
|
||||
|
||||
+ label {
|
||||
@apply bg-indigo-500;
|
||||
|
||||
> span:first-child {
|
||||
left: 22px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&:disabled {
|
||||
|
||||
+ label {
|
||||
@apply cursor-not-allowed bg-slate-100 border border-slate-200;
|
||||
|
||||
> span:first-child {
|
||||
@apply bg-slate-400;
|
||||
}
|
||||
}
|
||||
> span:first-child {
|
||||
@apply bg-slate-400;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,28 +1,28 @@
|
||||
// Typography
|
||||
.h1 {
|
||||
@apply text-4xl font-extrabold tracking-tighter;
|
||||
@apply text-4xl font-extrabold tracking-tighter;
|
||||
}
|
||||
|
||||
.h2 {
|
||||
@apply text-3xl font-extrabold tracking-tighter;
|
||||
@apply text-3xl font-extrabold tracking-tighter;
|
||||
}
|
||||
|
||||
.h3 {
|
||||
@apply text-3xl font-extrabold;
|
||||
@apply text-3xl font-extrabold;
|
||||
}
|
||||
|
||||
.h4 {
|
||||
@apply text-2xl font-extrabold tracking-tight;
|
||||
@apply text-2xl font-extrabold tracking-tight;
|
||||
}
|
||||
|
||||
@screen md {
|
||||
.h1 {
|
||||
@apply text-5xl;
|
||||
}
|
||||
.h1 {
|
||||
@apply text-5xl;
|
||||
}
|
||||
|
||||
.h2 {
|
||||
@apply text-4xl;
|
||||
}
|
||||
.h2 {
|
||||
@apply text-4xl;
|
||||
}
|
||||
}
|
||||
|
||||
// Buttons
|
||||
@@ -30,30 +30,30 @@
|
||||
.btn-lg,
|
||||
.btn-sm,
|
||||
.btn-xs {
|
||||
@apply font-medium text-sm inline-flex items-center justify-center border border-transparent rounded leading-5 shadow-sm transition duration-150 ease-in-out;
|
||||
@apply font-medium text-sm inline-flex items-center justify-center border border-transparent rounded leading-5 shadow-sm transition duration-150 ease-in-out;
|
||||
}
|
||||
|
||||
.btn {
|
||||
@apply px-3 py-2;
|
||||
@apply px-3 py-2;
|
||||
}
|
||||
|
||||
.btn-lg {
|
||||
@apply px-4 py-3;
|
||||
@apply px-4 py-3;
|
||||
}
|
||||
|
||||
.btn-sm {
|
||||
@apply px-2 py-1;
|
||||
@apply px-2 py-1;
|
||||
}
|
||||
|
||||
.btn-xs {
|
||||
@apply px-2 py-0.5;
|
||||
@apply px-2 py-0.5;
|
||||
}
|
||||
|
||||
// Forms
|
||||
input[type="search"]::-webkit-search-decoration,
|
||||
input[type="search"]::-webkit-search-cancel-button,
|
||||
input[type="search"]::-webkit-search-results-button,
|
||||
input[type="search"]::-webkit-search-results-decoration {
|
||||
input[type='search']::-webkit-search-decoration,
|
||||
input[type='search']::-webkit-search-cancel-button,
|
||||
input[type='search']::-webkit-search-results-button,
|
||||
input[type='search']::-webkit-search-results-decoration {
|
||||
-webkit-appearance: none;
|
||||
}
|
||||
|
||||
@@ -63,7 +63,7 @@ input[type="search"]::-webkit-search-results-decoration {
|
||||
.form-select,
|
||||
.form-checkbox,
|
||||
.form-radio {
|
||||
@apply text-sm text-slate-800 bg-white border;
|
||||
@apply text-sm text-slate-800 bg-white border;
|
||||
}
|
||||
|
||||
.form-input,
|
||||
@@ -71,28 +71,28 @@ input[type="search"]::-webkit-search-results-decoration {
|
||||
.form-multiselect,
|
||||
.form-select,
|
||||
.form-checkbox {
|
||||
@apply rounded;
|
||||
@apply rounded;
|
||||
}
|
||||
|
||||
.form-input,
|
||||
.form-textarea,
|
||||
.form-multiselect,
|
||||
.form-select {
|
||||
@apply leading-5 py-2 px-3 border-slate-200 hover:border-slate-300 focus:border-indigo-300 shadow-sm;
|
||||
@apply leading-5 py-2 px-3 border-slate-200 hover:border-slate-300 focus:border-indigo-300 shadow-sm;
|
||||
}
|
||||
|
||||
.form-input,
|
||||
.form-textarea {
|
||||
@apply placeholder-slate-400;
|
||||
@apply placeholder-slate-400;
|
||||
}
|
||||
|
||||
.form-select {
|
||||
@apply pr-10;
|
||||
@apply pr-10;
|
||||
}
|
||||
|
||||
.form-checkbox,
|
||||
.form-radio {
|
||||
@apply text-indigo-500 border border-slate-300;
|
||||
@apply text-indigo-500 border border-slate-300;
|
||||
}
|
||||
|
||||
/* Chrome, Safari and Opera */
|
||||
@@ -101,6 +101,6 @@ input[type="search"]::-webkit-search-results-decoration {
|
||||
}
|
||||
|
||||
.no-scrollbar {
|
||||
-ms-overflow-style: none; /* IE and Edge */
|
||||
scrollbar-width: none; /* Firefox */
|
||||
-ms-overflow-style: none; /* IE and Edge */
|
||||
scrollbar-width: none; /* Firefox */
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
|
||||
// Additional styles
|
||||
@import 'additional-styles/utility-patterns.scss';
|
||||
@import 'additional-styles/range-slider.scss';
|
||||
@import 'additional-styles/toggle-switch.scss';
|
||||
|
||||
@@ -1,95 +1,112 @@
|
||||
function createBlob(options) {
|
||||
let points = [];
|
||||
let slice = (Math.PI * 2) / options.numPoints;
|
||||
let startAngle = 0;
|
||||
|
||||
let points = [];
|
||||
let slice = (Math.PI * 2) / options.numPoints;
|
||||
let startAngle = 0;
|
||||
for (let i = 0; i < options.subkey.length; i++) {
|
||||
let angle = startAngle + i * slice;
|
||||
let rnd = Number('0x' + options.subkey.substring(i + 0, i + 1));
|
||||
let point = {
|
||||
x: options.centerX + Math.cos(angle) * (options.radius + rnd),
|
||||
y: options.centerY + Math.sin(angle) * (options.radius + rnd),
|
||||
};
|
||||
points.push(point);
|
||||
}
|
||||
|
||||
for (let i = 0; i < options.subkey.length; i++) {
|
||||
let angle = startAngle + i * slice;
|
||||
let rnd = Number("0x"+options.subkey.substring(i+0,i+1));
|
||||
let point = {
|
||||
x: options.centerX + Math.cos(angle) * (options.radius + rnd),
|
||||
y: options.centerY + Math.sin(angle) * (options.radius + rnd)
|
||||
};
|
||||
points.push(point);
|
||||
}
|
||||
let size = points.length;
|
||||
let path = 'M' + points[0].x + ' ' + points[0].y + ' C';
|
||||
|
||||
let size = points.length;
|
||||
let path = "M" + points[0].x + " " + points[0].y + " C";
|
||||
for (let i = 0; i < size; i++) {
|
||||
let p0 = points[(i - 1 + size) % size];
|
||||
let p1 = points[i];
|
||||
let p2 = points[(i + 1) % size];
|
||||
let p3 = points[(i + 2) % size];
|
||||
|
||||
for (let i = 0; i < size; i++) {
|
||||
let p0 = points[(i - 1 + size) % size];
|
||||
let p1 = points[i];
|
||||
let p2 = points[(i + 1) % size];
|
||||
let p3 = points[(i + 2) % size];
|
||||
let x1 = p1.x + (p2.x - p0.x) / 6;
|
||||
let y1 = p1.y + (p2.y - p0.y) / 6;
|
||||
|
||||
let x1 = p1.x + (p2.x - p0.x) / 6;
|
||||
let y1 = p1.y + (p2.y - p0.y) / 6;
|
||||
let x2 = p2.x - (p3.x - p1.x) / 6;
|
||||
let y2 = p2.y - (p3.y - p1.y) / 6;
|
||||
|
||||
let x2 = p2.x - (p3.x - p1.x) / 6;
|
||||
let y2 = p2.y - (p3.y - p1.y) / 6;
|
||||
path += ' ' + x1 + ' ' + y1 + ' ' + x2 + ' ' + y2 + ' ' + p2.x + ' ' + p2.y;
|
||||
}
|
||||
|
||||
path += " " + x1 + " " + y1 + " " + x2 + " " + y2 + " " + p2.x + " " + p2.y;
|
||||
}
|
||||
|
||||
return path + "z";
|
||||
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);
|
||||
//pubKey = "73f47d4929d7b2b6598ca4999d52567f9bb5aef3e353e0a66b468096db6e4e88"
|
||||
if (!localStorage.getItem('svgKey')) {
|
||||
localStorage.setItem('svgKey', `${pubKey}`)
|
||||
}
|
||||
let particles = [];
|
||||
let gradients = ['#000000'];
|
||||
let defs = [];
|
||||
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"
|
||||
let particles = [];
|
||||
let gradients = ['#000000'];
|
||||
let defs = [];
|
||||
|
||||
for (let a = 0; a<64; a = a + 8) {
|
||||
let blob = createBlob({
|
||||
numPoints: 8,
|
||||
centerX: 256,
|
||||
centerY: 256-a*4,
|
||||
radius: 16,
|
||||
subkey: pubKey.substring(a,a + 8)
|
||||
});
|
||||
for (let a = 0; a < 64; a = a + 8) {
|
||||
let blob = createBlob({
|
||||
numPoints: 8,
|
||||
centerX: 256,
|
||||
centerY: 256 - a * 4,
|
||||
radius: 16,
|
||||
subkey: pubKey.substring(a, a + 8),
|
||||
});
|
||||
|
||||
let color = "#" + pubKey.substring(a+2,a+8);
|
||||
let width = Number("0x"+pubKey.substring(a,a+1));
|
||||
let opacity = Number("0x"+pubKey.substring(a+1,a+2))/8;
|
||||
let color = '#' + pubKey.substring(a + 2, a + 8);
|
||||
let width = Number('0x' + pubKey.substring(a, a + 1));
|
||||
let opacity = Number('0x' + pubKey.substring(a + 1, a + 2)) / 8;
|
||||
|
||||
gradients.push(color);
|
||||
defs.push(`<radialGradient id="a-${a}" cx="0" cy="0" r="0.75" fx="0.35" fy="0.5" spreadMethod="reflect"><stop offset="0%" stop-color="${gradients[gradients.length-1]}"/><stop offset="100%" stop-color="${gradients[gradients.length]}"/></radialGradient>`);
|
||||
particles.push(`<path d="${blob}" stroke="url(#a-${a})" stroke-width="${width}" stroke-opacity = "${opacity}" fill="transparent"/>`);
|
||||
gradients.push(color);
|
||||
defs.push(
|
||||
`<radialGradient id="a-${a}" cx="0" cy="0" r="0.75" fx="0.35" fy="0.5" spreadMethod="reflect"><stop offset="0%" stop-color="${
|
||||
gradients[gradients.length - 1]
|
||||
}"/><stop offset="100%" stop-color="${
|
||||
gradients[gradients.length]
|
||||
}"/></radialGradient>`
|
||||
);
|
||||
particles.push(
|
||||
`<path d="${blob}" stroke="url(#a-${a})" stroke-width="${width}" stroke-opacity = "${opacity}" fill="transparent"/>`
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
let ph = "";
|
||||
let off = 4 + Number("0x"+pubKey.substring(0,1));
|
||||
let rotate = 0;
|
||||
for (var i = 0; i < off; i++){
|
||||
ph = ph + `<use xlink:href="#pattern-${pubKey}" mask="url(#mask)" class="segment" style="transform-origin:center center;transform: scaleY(1) rotate(${rotate}deg)"></use>,` + "\n";
|
||||
rotate = rotate + 360/off;
|
||||
}
|
||||
|
||||
var svg = [
|
||||
'<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="512" height="512" preserveAspectRatio="xMidYMid slice" viewBox="0 0 512 512">',
|
||||
'<defs>',
|
||||
'<radialGradient id="e" cx="0" cy="0" r="0.75" fx="0.35" fy="0.5" spreadMethod="reflect">',
|
||||
'<stop offset="0%" stop-color="red"/>',
|
||||
'<stop offset="100%" stop-color="blue"/>',
|
||||
'</radialGradient>',defs.join('\n'),
|
||||
'</defs>',
|
||||
'<symbol id="pattern-' + pubKey + '">',
|
||||
particles.join(''),
|
||||
'</symbol>',
|
||||
'<g style="transform-origin:center center; transform: rotate(' + pubKey + 'deg)">',
|
||||
ph,
|
||||
'</g>',
|
||||
'</svg>',
|
||||
].join('');
|
||||
return raw ? svg : 'data:image/svg+xml;base64,' + btoa(svg);
|
||||
};
|
||||
let ph = '';
|
||||
let off = 4 + Number('0x' + pubKey.substring(0, 1));
|
||||
let rotate = 0;
|
||||
for (var i = 0; i < off; i++) {
|
||||
ph =
|
||||
ph +
|
||||
`<use xlink:href="#pattern-${pubKey}" mask="url(#mask)" class="segment" style="transform-origin:center center;transform: scaleY(1) rotate(${rotate}deg)"></use>,` +
|
||||
'\n';
|
||||
rotate = rotate + 360 / off;
|
||||
}
|
||||
|
||||
var svg = [
|
||||
'<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="512" height="512" preserveAspectRatio="xMidYMid slice" viewBox="0 0 512 512">',
|
||||
'<defs>',
|
||||
'<radialGradient id="e" cx="0" cy="0" r="0.75" fx="0.35" fy="0.5" spreadMethod="reflect">',
|
||||
'<stop offset="0%" stop-color="red"/>',
|
||||
'<stop offset="100%" stop-color="blue"/>',
|
||||
'</radialGradient>',
|
||||
defs.join('\n'),
|
||||
'</defs>',
|
||||
'<symbol id="pattern-' + pubKey + '">',
|
||||
particles.join(''),
|
||||
'</symbol>',
|
||||
'<g style="transform-origin:center center; transform: rotate(' +
|
||||
pubKey +
|
||||
'deg)">',
|
||||
ph,
|
||||
'</g>',
|
||||
'</svg>',
|
||||
].join('');
|
||||
return raw ? svg : 'data:image/svg+xml;base64,' + btoa(svg);
|
||||
};
|
||||
})();
|
||||
|
||||
BIN
src/images/service_icon.png
Normal file
|
After Width: | Height: | Size: 912 B |
BIN
src/images/vpn_server_icon.png
Normal file
|
After Width: | Height: | Size: 623 B |
BIN
src/images/vpn_service.png
Normal file
|
After Width: | Height: | Size: 5.8 KiB |
40
src/main.jsx
@@ -1,13 +1,29 @@
|
||||
import React from 'react'
|
||||
import ReactDOM from 'react-dom'
|
||||
import { BrowserRouter as Router } from 'react-router-dom'
|
||||
import App from './App'
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import { Buffer } from 'buffer';
|
||||
import { HashRouter as Router } from 'react-router-dom';
|
||||
import App from './App';
|
||||
import { store } from './store/store';
|
||||
import { fetchWrapper } from './shared/fetchWrapper';
|
||||
|
||||
ReactDOM.render(
|
||||
<React.StrictMode>
|
||||
<Router>
|
||||
<App />
|
||||
</Router>
|
||||
</React.StrictMode>,
|
||||
document.getElementById('root')
|
||||
)
|
||||
globalThis.Buffer = Buffer;
|
||||
|
||||
window.store = store;
|
||||
|
||||
BigInt.prototype.toJSON = function () {
|
||||
return this.toString();
|
||||
};
|
||||
|
||||
fetch('settings.json')
|
||||
.then((e) => e.json())
|
||||
.then((data) => (fetchWrapper.baseUrl = data.API_URL))
|
||||
.then(() =>
|
||||
ReactDOM.render(
|
||||
<React.StrictMode>
|
||||
<Router>
|
||||
<App />
|
||||
</Router>
|
||||
</React.StrictMode>,
|
||||
document.getElementById('root')
|
||||
)
|
||||
);
|
||||
|
||||
@@ -1,92 +0,0 @@
|
||||
import React, { useState } from 'react';
|
||||
|
||||
import Sidebar from '../partials/Sidebar';
|
||||
import Header from '../partials/Header';
|
||||
import Datepicker from '../components/Datepicker';
|
||||
import AnalyticsCard01 from '../partials/analytics/AnalyticsCard01';
|
||||
import AnalyticsCard02 from '../partials/analytics/AnalyticsCard02';
|
||||
import AnalyticsCard03 from '../partials/analytics/AnalyticsCard03';
|
||||
import AnalyticsCard04 from '../partials/analytics/AnalyticsCard04';
|
||||
import AnalyticsCard05 from '../partials/analytics/AnalyticsCard05';
|
||||
import AnalyticsCard06 from '../partials/analytics/AnalyticsCard06';
|
||||
import AnalyticsCard07 from '../partials/analytics/AnalyticsCard07';
|
||||
import AnalyticsCard08 from '../partials/analytics/AnalyticsCard08';
|
||||
import AnalyticsCard09 from '../partials/analytics/AnalyticsCard09';
|
||||
import AnalyticsCard10 from '../partials/analytics/AnalyticsCard10';
|
||||
import AnalyticsCard11 from '../partials/analytics/AnalyticsCard11';
|
||||
|
||||
function Analytics() {
|
||||
|
||||
const [sidebarOpen, setSidebarOpen] = useState(false);
|
||||
|
||||
return (
|
||||
<div className="flex h-screen overflow-hidden">
|
||||
|
||||
{/* Sidebar */}
|
||||
<Sidebar sidebarOpen={sidebarOpen} setSidebarOpen={setSidebarOpen} />
|
||||
|
||||
{/* Content area */}
|
||||
<div className="relative flex flex-col flex-1 overflow-y-auto overflow-x-hidden">
|
||||
|
||||
{/* Site header */}
|
||||
<Header sidebarOpen={sidebarOpen} setSidebarOpen={setSidebarOpen} />
|
||||
|
||||
<main>
|
||||
<div className="px-4 sm:px-6 lg:px-8 py-8 w-full max-w-9xl mx-auto">
|
||||
|
||||
{/* Page header */}
|
||||
<div className="sm:flex sm:justify-between sm:items-center mb-8">
|
||||
|
||||
{/* Left: Title */}
|
||||
<div className="mb-4 sm:mb-0">
|
||||
<h1 className="text-2xl md:text-3xl text-slate-800 font-bold">Analytics ✨</h1>
|
||||
</div>
|
||||
|
||||
{/* Right: Actions */}
|
||||
<div className="grid grid-flow-col sm:auto-cols-max justify-start sm:justify-end gap-2">
|
||||
|
||||
{/* Datepicker built with flatpickr */}
|
||||
<Datepicker align="right" />
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
{/* Cards */}
|
||||
<div className="grid grid-cols-12 gap-6">
|
||||
|
||||
{/* Line chart (Analytics) */}
|
||||
<AnalyticsCard01 />
|
||||
{/* Line chart (Active Users Right Now) */}
|
||||
<AnalyticsCard02 />
|
||||
{/* Stacked bar chart (Acquisition Channels) */}
|
||||
<AnalyticsCard03 />
|
||||
{/* Horizontal bar chart (Audience Overview) */}
|
||||
<AnalyticsCard04 />
|
||||
{/* Report card (Top Channels) */}
|
||||
<AnalyticsCard05 />
|
||||
{/* Report card (Top Pages) */}
|
||||
<AnalyticsCard06 />
|
||||
{/* Report card (Top Countries) */}
|
||||
<AnalyticsCard07 />
|
||||
{/* Doughnut chart (Sessions By Device) */}
|
||||
<AnalyticsCard08 />
|
||||
{/* Doughnut chart (Visit By Age Category) */}
|
||||
<AnalyticsCard09 />
|
||||
{/* Polar chart (Sessions By Gender) */}
|
||||
<AnalyticsCard10 />
|
||||
{/* Table (Top Products) */}
|
||||
<AnalyticsCard11 />
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</main>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default Analytics;
|
||||
@@ -1,105 +0,0 @@
|
||||
import React, {useEffect, useState} from 'react';
|
||||
|
||||
import Sidebar from '../partials/Sidebar';
|
||||
import Header from '../partials/Header';
|
||||
import WelcomeBanner from '../partials/dashboard/WelcomeBanner';
|
||||
import DashboardAvatars from '../partials/dashboard/DashboardAvatars';
|
||||
import FilterButton from '../components/DropdownFilter';
|
||||
import Datepicker from '../components/Datepicker';
|
||||
import DashboardCard01 from '../partials/dashboard/DashboardCard01';
|
||||
import DashboardCard02 from '../partials/dashboard/DashboardCard02';
|
||||
import DashboardCard03 from '../partials/dashboard/DashboardCard03';
|
||||
import DashboardCard04 from '../partials/dashboard/DashboardCard04';
|
||||
import DashboardCard05 from '../partials/dashboard/DashboardCard05';
|
||||
import DashboardCard06 from '../partials/dashboard/DashboardCard06';
|
||||
import DashboardCard07 from '../partials/dashboard/DashboardCard07';
|
||||
import DashboardCard08 from '../partials/dashboard/DashboardCard08';
|
||||
import DashboardCard09 from '../partials/dashboard/DashboardCard09';
|
||||
import DashboardCard10 from '../partials/dashboard/DashboardCard10';
|
||||
import DashboardCard11 from '../partials/dashboard/DashboardCard11';
|
||||
|
||||
function Dashboard() {
|
||||
useEffect(() => {
|
||||
localStorage.setItem('svgKey', '')
|
||||
}, [])
|
||||
const [sidebarOpen, setSidebarOpen] = useState(false);
|
||||
|
||||
return (
|
||||
<div className="flex h-screen overflow-hidden">
|
||||
|
||||
{/* Sidebar */}
|
||||
<Sidebar sidebarOpen={sidebarOpen} setSidebarOpen={setSidebarOpen} />
|
||||
|
||||
{/* Content area */}
|
||||
<div className="relative flex flex-col flex-1 overflow-y-auto overflow-x-hidden">
|
||||
|
||||
{/* Site header */}
|
||||
<Header sidebarOpen={sidebarOpen} setSidebarOpen={setSidebarOpen} />
|
||||
|
||||
<main>
|
||||
<div className="px-4 sm:px-6 lg:px-8 py-8 w-full max-w-9xl mx-auto">
|
||||
|
||||
{/* Welcome banner */}
|
||||
<WelcomeBanner />
|
||||
|
||||
{/* Dashboard actions */}
|
||||
<div className="sm:flex sm:justify-between sm:items-center mb-8">
|
||||
|
||||
{/* Left: Avatars */}
|
||||
<DashboardAvatars />
|
||||
|
||||
{/* Right: Actions */}
|
||||
<div className="grid grid-flow-col sm:auto-cols-max justify-start sm:justify-end gap-2">
|
||||
{/* Filter button */}
|
||||
<FilterButton align="right" />
|
||||
{/* Datepicker built with flatpickr */}
|
||||
<Datepicker align="right" />
|
||||
{/* Add view button */}
|
||||
<button className="btn bg-indigo-500 hover:bg-indigo-600 text-white">
|
||||
<svg className="w-4 h-4 fill-current opacity-50 shrink-0" viewBox="0 0 16 16">
|
||||
<path d="M15 7H9V1c0-.6-.4-1-1-1S7 .4 7 1v6H1c-.6 0-1 .4-1 1s.4 1 1 1h6v6c0 .6.4 1 1 1s1-.4 1-1V9h6c.6 0 1-.4 1-1s-.4-1-1-1z" />
|
||||
</svg>
|
||||
<span className="hidden xs:block ml-2">Add View</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
{/* Cards */}
|
||||
<div className="grid grid-cols-12 gap-6">
|
||||
|
||||
{/* Line chart (Acme Plus) */}
|
||||
<DashboardCard01 />
|
||||
{/* Line chart (Acme Advanced) */}
|
||||
<DashboardCard02 />
|
||||
{/* Line chart (Acme Professional) */}
|
||||
<DashboardCard03 />
|
||||
{/* Bar chart (Direct vs Indirect) */}
|
||||
<DashboardCard04 />
|
||||
{/* Line chart (Real Time Value) */}
|
||||
<DashboardCard05 />
|
||||
{/* Doughnut chart (Top Countries) */}
|
||||
<DashboardCard06 />
|
||||
{/* Table (Top Channels) */}
|
||||
<DashboardCard07 />
|
||||
{/* Line chart (Sales Over Time) */}
|
||||
<DashboardCard08 />
|
||||
{/* Stacked bar chart (Sales VS Refunds) */}
|
||||
<DashboardCard09 />
|
||||
{/* Card (Recent Activity) */}
|
||||
<DashboardCard10 />
|
||||
{/* Card (Income/Expenses) */}
|
||||
<DashboardCard11 />
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</main>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default Dashboard;
|
||||
@@ -1,104 +0,0 @@
|
||||
import React, { useState } from 'react';
|
||||
|
||||
import Sidebar from '../partials/Sidebar';
|
||||
import Header from '../partials/Header';
|
||||
import Datepicker from '../components/Datepicker';
|
||||
import FintechIntro from '../partials/fintech/FintechIntro';
|
||||
import FintechCard01 from '../partials/fintech/FintechCard01';
|
||||
import FintechCard02 from '../partials/fintech/FintechCard02';
|
||||
import FintechCard03 from '../partials/fintech/FintechCard03';
|
||||
import FintechCard04 from '../partials/fintech/FintechCard04';
|
||||
import FintechCard05 from '../partials/fintech/FintechCard05';
|
||||
import FintechCard06 from '../partials/fintech/FintechCard06';
|
||||
import FintechCard07 from '../partials/fintech/FintechCard07';
|
||||
import FintechCard08 from '../partials/fintech/FintechCard08';
|
||||
import FintechCard09 from '../partials/fintech/FintechCard09';
|
||||
import FintechCard10 from '../partials/fintech/FintechCard10';
|
||||
import FintechCard11 from '../partials/fintech/FintechCard11';
|
||||
import FintechCard12 from '../partials/fintech/FintechCard12';
|
||||
import FintechCard13 from '../partials/fintech/FintechCard13';
|
||||
import FintechCard14 from '../partials/fintech/FintechCard14';
|
||||
|
||||
function Fintech() {
|
||||
|
||||
const [sidebarOpen, setSidebarOpen] = useState(false);
|
||||
|
||||
return (
|
||||
<div className='flex h-screen overflow-hidden'>
|
||||
{/* Sidebar */}
|
||||
<Sidebar sidebarOpen={sidebarOpen} setSidebarOpen={setSidebarOpen} />
|
||||
|
||||
{/* Content area */}
|
||||
<div className='relative flex flex-col flex-1 overflow-y-auto overflow-x-hidden'>
|
||||
{/* Site header */}
|
||||
<Header sidebarOpen={sidebarOpen} setSidebarOpen={setSidebarOpen} />
|
||||
|
||||
<main>
|
||||
<div className='px-4 sm:px-6 lg:px-8 py-8 w-full max-w-9xl mx-auto'>
|
||||
|
||||
{/* Page header */}
|
||||
<div className='sm:flex sm:justify-between sm:items-center mb-5'>
|
||||
|
||||
{/* Left: Title */}
|
||||
<div className='mb-4 sm:mb-0'>
|
||||
<h1 className='text-2xl md:text-3xl text-slate-800 font-bold'>Fintech ✨</h1>
|
||||
</div>
|
||||
|
||||
{/* Right: Actions */}
|
||||
<div className='grid grid-flow-col sm:auto-cols-max justify-start sm:justify-end gap-2'>
|
||||
|
||||
{/* Datepicker built with flatpickr */}
|
||||
<Datepicker align='right' />
|
||||
|
||||
{/* Add account button */}
|
||||
<button className='btn bg-indigo-500 hover:bg-indigo-600 text-white'>
|
||||
<svg className='w-4 h-4 fill-current opacity-50 shrink-0' viewBox='0 0 16 16'>
|
||||
<path d='M15 7H9V1c0-.6-.4-1-1-1S7 .4 7 1v6H1c-.6 0-1 .4-1 1s.4 1 1 1h6v6c0 .6.4 1 1 1s1-.4 1-1V9h6c.6 0 1-.4 1-1s-.4-1-1-1z' />
|
||||
</svg>
|
||||
<span className='hidden xs:block ml-2'>Add Account</span>
|
||||
</button>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
{/* Cards */}
|
||||
<div className='grid grid-cols-12 gap-6'>
|
||||
|
||||
{/* Page Intro */}
|
||||
<FintechIntro />
|
||||
{/* Line chart (Portfolio Returns) */}
|
||||
<FintechCard01 />
|
||||
{/* Credit Card */}
|
||||
<FintechCard02 />
|
||||
{/* Bar chart (Cash Flow) */}
|
||||
<FintechCard03 />
|
||||
{/* Horizontal bar chart (Cash Flow by Account) */}
|
||||
<FintechCard04 />
|
||||
{/* Table (Recent Expenses) */}
|
||||
<FintechCard05 />
|
||||
{/* Table (Recent Earnings) */}
|
||||
<FintechCard06 />
|
||||
{/* Line chart (Saving Goals) */}
|
||||
<FintechCard07 />
|
||||
{/* Line chart (Growth Portfolio) */}
|
||||
<FintechCard08 />
|
||||
{/* Pie chart (Portfolio Value) */}
|
||||
<FintechCard09 />
|
||||
{/* Line charts (Stock graphs) */}
|
||||
<FintechCard10 />
|
||||
<FintechCard11 />
|
||||
<FintechCard12 />
|
||||
<FintechCard13 />
|
||||
{/* Table (Market Trends) */}
|
||||
<FintechCard14 />
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default Fintech;
|
||||
@@ -1,55 +0,0 @@
|
||||
import React, { useState, useEffect, useRef } from 'react';
|
||||
|
||||
import Sidebar from '../partials/Sidebar';
|
||||
import Header from '../partials/Header';
|
||||
import MessagesSidebar from '../partials/messages/MessagesSidebar';
|
||||
import MessagesHeader from '../partials/messages/MessagesHeader';
|
||||
import MessagesBody from '../partials/messages/MessagesBody';
|
||||
import MessagesFooter from '../partials/messages/MessagesFooter';
|
||||
|
||||
function Messages() {
|
||||
|
||||
const contentArea = useRef(null)
|
||||
|
||||
const [sidebarOpen, setSidebarOpen] = useState(false);
|
||||
const [msgSidebarOpen, setMsgSidebarOpen] = useState(true);
|
||||
|
||||
useEffect(() => {
|
||||
contentArea.current.scrollTop = 99999999
|
||||
}, [msgSidebarOpen]); // automatically scroll the chat and make the most recent message visible
|
||||
|
||||
return (
|
||||
<div className="flex h-screen overflow-hidden">
|
||||
|
||||
{/* Sidebar */}
|
||||
<Sidebar sidebarOpen={sidebarOpen} setSidebarOpen={setSidebarOpen} />
|
||||
|
||||
{/* Content area */}
|
||||
<div className="relative flex flex-col flex-1 overflow-y-auto overflow-x-hidden" ref={contentArea}>
|
||||
|
||||
{/* Site header */}
|
||||
<Header sidebarOpen={sidebarOpen} setSidebarOpen={setSidebarOpen} />
|
||||
|
||||
<main>
|
||||
<div className="relative flex">
|
||||
|
||||
{/* Messages sidebar */}
|
||||
<MessagesSidebar msgSidebarOpen={msgSidebarOpen} setMsgSidebarOpen={setMsgSidebarOpen} />
|
||||
|
||||
{/* Messages body */}
|
||||
<div className={`grow flex flex-col md:translate-x-0 transform transition-transform duration-300 ease-in-out ${msgSidebarOpen ? 'translate-x-1/3' : 'translate-x-0'}`}>
|
||||
<MessagesHeader msgSidebarOpen={msgSidebarOpen} setMsgSidebarOpen={setMsgSidebarOpen} />
|
||||
<MessagesBody />
|
||||
<MessagesFooter />
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</main>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default Messages;
|
||||
@@ -1,51 +1,84 @@
|
||||
import React from 'react';
|
||||
import React, { useEffect } from 'react';
|
||||
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 Logo from '../images/logo.png';
|
||||
import { observer } from 'mobx-react-lite';
|
||||
import { store } from '../store/store';
|
||||
import { Navigate } from 'react-router-dom';
|
||||
|
||||
const Onboarding1 = observer(() => {
|
||||
useEffect(() => {
|
||||
store.clearDataRegistration();
|
||||
}, []);
|
||||
|
||||
if (store.passPhrase)
|
||||
return <Navigate to="/digitalId/profile-id" replace={true} />;
|
||||
|
||||
function Onboarding1() {
|
||||
return (
|
||||
<main className="bg-white">
|
||||
|
||||
<div className="relative flex">
|
||||
|
||||
{/* Content */}
|
||||
<div className="w-full md:w-1/2">
|
||||
|
||||
<div className="min-h-screen h-full flex flex-col after:flex-1">
|
||||
|
||||
<div className="flex-1">
|
||||
|
||||
{/* Header */}
|
||||
<div className="flex items-center justify-between h-16 px-4 sm:px-6 lg:px-8">
|
||||
{/* Logo */}
|
||||
<Link className="block" to="/">
|
||||
<img alt='logo' src={Logo} width="89" height="32"/>
|
||||
<Link className="block" to="/dashboard">
|
||||
<img alt="logo" src={Logo} width="89" height="32" />
|
||||
</Link>
|
||||
<div className="text-sm">
|
||||
Have an account? <Link className="font-medium text-indigo-500 hover:text-indigo-600" to="/signin">Sign In</Link>
|
||||
Have an account?{' '}
|
||||
<Link
|
||||
className="font-medium text-indigo-500 hover:text-indigo-600"
|
||||
to="/signIn"
|
||||
>
|
||||
Sign In
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Progress bar */}
|
||||
<div className="px-4 pt-12 pb-8">
|
||||
<div className="px-4 pt-12 pb-[142px]">
|
||||
<div className="max-w-md mx-auto w-full">
|
||||
<div className="relative">
|
||||
<div className="absolute left-0 top-1/2 -mt-px w-full h-0.5 bg-slate-200" aria-hidden="true"></div>
|
||||
<div
|
||||
className="absolute left-0 top-1/2 -mt-px w-full h-0.5 bg-slate-200"
|
||||
aria-hidden="true"
|
||||
></div>
|
||||
<ul className="relative flex justify-between w-full">
|
||||
<li>
|
||||
<Link className="flex items-center justify-center w-6 h-6 rounded-full text-xs font-semibold bg-indigo-500 text-white" to="/onboarding-1">1</Link>
|
||||
<span
|
||||
className="flex items-center justify-center w-6 h-6 rounded-full text-xs font-semibold bg-indigo-500 text-white"
|
||||
to="/"
|
||||
>
|
||||
1
|
||||
</span>
|
||||
</li>
|
||||
<li>
|
||||
<Link className="flex items-center justify-center w-6 h-6 rounded-full text-xs font-semibold bg-slate-100 text-slate-500" to="/onboarding-2">2</Link>
|
||||
<span
|
||||
className="flex items-center justify-center w-6 h-6 rounded-full text-xs font-semibold bg-slate-100 text-slate-500"
|
||||
to="/onboarding-2"
|
||||
>
|
||||
2
|
||||
</span>
|
||||
</li>
|
||||
<li>
|
||||
<Link className="flex items-center justify-center w-6 h-6 rounded-full text-xs font-semibold bg-slate-100 text-slate-500" to="/onboarding-3">3</Link>
|
||||
<span
|
||||
className="flex items-center justify-center w-6 h-6 rounded-full text-xs font-semibold bg-slate-100 text-slate-500"
|
||||
to="/onboarding-3"
|
||||
>
|
||||
3
|
||||
</span>
|
||||
</li>
|
||||
<li>
|
||||
<Link className="flex items-center justify-center w-6 h-6 rounded-full text-xs font-semibold bg-slate-100 text-slate-500" to="/onboarding-4">4</Link>
|
||||
<span
|
||||
className="flex items-center justify-center w-6 h-6 rounded-full text-xs font-semibold bg-slate-100 text-slate-500"
|
||||
to="/onboarding-4"
|
||||
>
|
||||
4
|
||||
</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
@@ -55,76 +88,159 @@ function Onboarding1() {
|
||||
|
||||
<div className="px-4 py-8">
|
||||
<div className="max-w-md mx-auto">
|
||||
|
||||
<h1 className="text-3xl text-slate-800 font-bold mb-6">Tell us about your company ✨</h1>
|
||||
<h1 className="text-3xl text-slate-800 font-bold mb-12">
|
||||
Tell us about your company ✨
|
||||
</h1>
|
||||
{/* Form */}
|
||||
<form>
|
||||
<div>
|
||||
<div className="sm:flex space-y-3 sm:space-y-0 sm:space-x-4 mb-8">
|
||||
<label className="flex-1 relative block cursor-pointer">
|
||||
<input type="radio" name="radio-buttons" className="peer sr-only" defaultChecked />
|
||||
<input
|
||||
type="radio"
|
||||
name="radio-buttons"
|
||||
className="peer sr-only"
|
||||
defaultChecked
|
||||
/>
|
||||
<div className="h-full text-center bg-white px-4 py-6 rounded border border-slate-200 hover:border-slate-300 shadow-sm duration-150 ease-in-out">
|
||||
<svg className="inline-flex w-10 h-10 shrink-0 fill-current mb-2" viewBox="0 0 40 40">
|
||||
<circle className="text-indigo-100" cx="20" cy="20" r="20" />
|
||||
<path className="text-indigo-500" d="m26.371 23.749-3.742-1.5a1 1 0 0 1-.629-.926v-.878A3.982 3.982 0 0 0 24 17v-1.828A4.087 4.087 0 0 0 20 11a4.087 4.087 0 0 0-4 4.172V17a3.982 3.982 0 0 0 2 3.445v.878a1 1 0 0 1-.629.928l-3.742 1.5a1 1 0 0 0-.629.926V27a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1v-2.323a1 1 0 0 0-.629-.928Z" />
|
||||
<svg
|
||||
className="inline-flex w-10 h-10 shrink-0 fill-current mb-2"
|
||||
viewBox="0 0 40 40"
|
||||
>
|
||||
<circle
|
||||
className="text-indigo-100"
|
||||
cx="20"
|
||||
cy="20"
|
||||
r="20"
|
||||
/>
|
||||
<path
|
||||
className="text-indigo-500"
|
||||
d="m26.371 23.749-3.742-1.5a1 1 0 0 1-.629-.926v-.878A3.982 3.982 0 0 0 24 17v-1.828A4.087 4.087 0 0 0 20 11a4.087 4.087 0 0 0-4 4.172V17a3.982 3.982 0 0 0 2 3.445v.878a1 1 0 0 1-.629.928l-3.742 1.5a1 1 0 0 0-.629.926V27a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1v-2.323a1 1 0 0 0-.629-.928Z"
|
||||
/>
|
||||
</svg>
|
||||
<div className="font-medium text-slate-800 mb-1">Individual</div>
|
||||
<div className="text-sm">Lorem ipsum is place text commonly used.</div>
|
||||
<div className="font-semibold text-slate-800 mb-1">
|
||||
Individual
|
||||
</div>
|
||||
<div className="text-sm">
|
||||
Lorem ipsum is place text commonly used.
|
||||
</div>
|
||||
</div>
|
||||
<div className="absolute inset-0 border-2 border-transparent peer-checked:border-indigo-400 rounded pointer-events-none" aria-hidden="true"></div>
|
||||
<div
|
||||
className="absolute inset-0 border-2 border-transparent peer-checked:border-indigo-400 rounded pointer-events-none"
|
||||
aria-hidden="true"
|
||||
></div>
|
||||
</label>
|
||||
<label className="flex-1 relative block cursor-pointer">
|
||||
<input type="radio" name="radio-buttons" className="peer sr-only" />
|
||||
<input
|
||||
type="radio"
|
||||
name="radio-buttons"
|
||||
className="peer sr-only"
|
||||
/>
|
||||
<div className="h-full text-center bg-white px-4 py-6 rounded border border-slate-200 hover:border-slate-300 shadow-sm duration-150 ease-in-out">
|
||||
<svg className="inline-flex w-10 h-10 shrink-0 fill-current mb-2" viewBox="0 0 40 40">
|
||||
<circle className="text-indigo-100" cx="20" cy="20" r="20" />
|
||||
<path className="text-indigo-500" d="m26.371 23.749-3.742-1.5a1 1 0 0 1-.629-.926v-.878A3.982 3.982 0 0 0 24 17v-1.828A4.087 4.087 0 0 0 20 11a4.087 4.087 0 0 0-4 4.172V17a3.982 3.982 0 0 0 2 3.445v.878a1 1 0 0 1-.629.928l-3.742 1.5a1 1 0 0 0-.629.926V27a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1v-2.323a1 1 0 0 0-.629-.928Z" />
|
||||
<circle className="text-indigo-100" cx="20" cy="20" r="20" />
|
||||
<path className="text-indigo-300" d="m30.377 22.749-3.709-1.5a1 1 0 0 1-.623-.926v-.878A3.989 3.989 0 0 0 28.027 16v-1.828c.047-2.257-1.728-4.124-3.964-4.172-2.236.048-4.011 1.915-3.964 4.172V16a3.989 3.989 0 0 0 1.982 3.445v.878a1 1 0 0 1-.623.928c-.906.266-1.626.557-2.159.872-.533.315-1.3 1.272-2.299 2.872 1.131.453 6.075-.546 6.072.682V28a2.99 2.99 0 0 1-.182 1h7.119A.996.996 0 0 0 31 28v-4.323a1 1 0 0 0-.623-.928Z" />
|
||||
<path className="text-indigo-500" d="m22.371 24.749-3.742-1.5a1 1 0 0 1-.629-.926v-.878A3.982 3.982 0 0 0 20 18v-1.828A4.087 4.087 0 0 0 16 12a4.087 4.087 0 0 0-4 4.172V18a3.982 3.982 0 0 0 2 3.445v.878a1 1 0 0 1-.629.928l-3.742 1.5a1 1 0 0 0-.629.926V28a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1v-2.323a1 1 0 0 0-.629-.928Z" />
|
||||
<svg
|
||||
className="inline-flex w-10 h-10 shrink-0 fill-current mb-2"
|
||||
viewBox="0 0 40 40"
|
||||
>
|
||||
<circle
|
||||
className="text-indigo-100"
|
||||
cx="20"
|
||||
cy="20"
|
||||
r="20"
|
||||
/>
|
||||
<path
|
||||
className="text-indigo-500"
|
||||
d="m26.371 23.749-3.742-1.5a1 1 0 0 1-.629-.926v-.878A3.982 3.982 0 0 0 24 17v-1.828A4.087 4.087 0 0 0 20 11a4.087 4.087 0 0 0-4 4.172V17a3.982 3.982 0 0 0 2 3.445v.878a1 1 0 0 1-.629.928l-3.742 1.5a1 1 0 0 0-.629.926V27a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1v-2.323a1 1 0 0 0-.629-.928Z"
|
||||
/>
|
||||
<circle
|
||||
className="text-indigo-100"
|
||||
cx="20"
|
||||
cy="20"
|
||||
r="20"
|
||||
/>
|
||||
<path
|
||||
className="text-indigo-300"
|
||||
d="m30.377 22.749-3.709-1.5a1 1 0 0 1-.623-.926v-.878A3.989 3.989 0 0 0 28.027 16v-1.828c.047-2.257-1.728-4.124-3.964-4.172-2.236.048-4.011 1.915-3.964 4.172V16a3.989 3.989 0 0 0 1.982 3.445v.878a1 1 0 0 1-.623.928c-.906.266-1.626.557-2.159.872-.533.315-1.3 1.272-2.299 2.872 1.131.453 6.075-.546 6.072.682V28a2.99 2.99 0 0 1-.182 1h7.119A.996.996 0 0 0 31 28v-4.323a1 1 0 0 0-.623-.928Z"
|
||||
/>
|
||||
<path
|
||||
className="text-indigo-500"
|
||||
d="m22.371 24.749-3.742-1.5a1 1 0 0 1-.629-.926v-.878A3.982 3.982 0 0 0 20 18v-1.828A4.087 4.087 0 0 0 16 12a4.087 4.087 0 0 0-4 4.172V18a3.982 3.982 0 0 0 2 3.445v.878a1 1 0 0 1-.629.928l-3.742 1.5a1 1 0 0 0-.629.926V28a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1v-2.323a1 1 0 0 0-.629-.928Z"
|
||||
/>
|
||||
</svg>
|
||||
<div className="font-medium text-slate-800 mb-1">Organization</div>
|
||||
<div className="text-sm">Lorem ipsum is place text commonly used.</div>
|
||||
<div className="font-semibold text-slate-800 mb-1">
|
||||
Organization
|
||||
</div>
|
||||
<div className="text-sm">
|
||||
Lorem ipsum is place text commonly used.
|
||||
</div>
|
||||
</div>
|
||||
<div className="absolute inset-0 border-2 border-transparent peer-checked:border-indigo-400 rounded pointer-events-none" aria-hidden="true"></div>
|
||||
<div
|
||||
className="absolute inset-0 border-2 border-transparent peer-checked:border-indigo-400 rounded pointer-events-none"
|
||||
aria-hidden="true"
|
||||
></div>
|
||||
</label>
|
||||
</div>
|
||||
<div className="flex items-center justify-between space-x-6 mb-8">
|
||||
<div>
|
||||
<div className="font-medium text-slate-800 text-sm mb-1">💸 Lorem ipsum is place text commonly?</div>
|
||||
<div className="text-xs">Lorem ipsum is placeholder text commonly used in the graphic, print, and publishing industries for previewing layouts.</div>
|
||||
<div className="font-medium text-slate-800 text-sm mb-1">
|
||||
💸 Lorem ipsum is place text commonly?
|
||||
</div>
|
||||
<div className="text-xs font-normal leading-6">
|
||||
Lorem ipsum is placeholder text commonly used in the
|
||||
graphic, print, and publishing industries for previewing
|
||||
layouts.
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center">
|
||||
<div className="form-switch">
|
||||
<input type="checkbox" id="switch" className="sr-only" defaultChecked />
|
||||
<input
|
||||
type="checkbox"
|
||||
id="switch"
|
||||
className="sr-only"
|
||||
defaultChecked
|
||||
/>
|
||||
<label className="bg-slate-400" htmlFor="switch">
|
||||
<span className="bg-white shadow-sm" aria-hidden="true"></span>
|
||||
<span
|
||||
className="bg-white shadow-sm"
|
||||
aria-hidden="true"
|
||||
></span>
|
||||
<span className="sr-only">Switch label</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center justify-between">
|
||||
<Link className="btn bg-indigo-500 hover:bg-indigo-600 text-white ml-auto" to="/onboarding-2">Next Step -></Link>
|
||||
<button className="font-medium btn bg-indigo-500 hover:bg-indigo-600 text-white ml-auto">
|
||||
<Link to="/onboarding-2">Next Step -></Link>
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
{/* Image */}
|
||||
<div className="hidden md:block absolute top-0 bottom-0 right-0 md:w-1/2" aria-hidden="true">
|
||||
<img className="object-cover object-center w-full h-full" src={OnboardingImage} width="760" height="1024" alt="Onboarding" />
|
||||
<img className="absolute top-1/4 left-0 transform -translate-x-1/2 ml-8 hidden lg:block" src={OnboardingDecoration} width="218" height="224" alt="Authentication decoration" />
|
||||
<div
|
||||
className="hidden md:block absolute top-0 bottom-0 right-0 md:w-1/2"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<img
|
||||
className="object-cover object-center w-full h-full"
|
||||
src={OnboardingImage}
|
||||
width="760"
|
||||
height="1024"
|
||||
alt="Onboarding"
|
||||
/>
|
||||
<img
|
||||
className="absolute top-1/4 left-0 transform -translate-x-1/2 ml-8 hidden lg:block"
|
||||
src={OnboardingDecoration}
|
||||
width="218"
|
||||
height="224"
|
||||
alt="Authentication decoration"
|
||||
/>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</main>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
export default Onboarding1;
|
||||
|
||||
@@ -1,51 +1,124 @@
|
||||
import React from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
import React, { useEffect, useMemo, useState } from 'react';
|
||||
import { Link, useNavigate } from 'react-router-dom';
|
||||
import { observer } from 'mobx-react-lite';
|
||||
import { store } from '../store/store';
|
||||
import OnboardingImage from '../images/onboarding-image.jpg';
|
||||
import OnboardingDecoration from '../images/auth-decoration.png';
|
||||
import Logo from "../images/logo.png";
|
||||
import Logo from '../images/logo.png';
|
||||
|
||||
const Onboarding2 = observer(() => {
|
||||
const navigate = useNavigate();
|
||||
|
||||
const [dataRegistration, setDataRegistration] = useState({
|
||||
firstname: '',
|
||||
secondname: '',
|
||||
gender: '',
|
||||
birthdate: '',
|
||||
});
|
||||
|
||||
const fillingForm = useMemo(
|
||||
() =>
|
||||
!Object.keys(dataRegistration).find((item) => !dataRegistration[item]),
|
||||
[dataRegistration]
|
||||
);
|
||||
|
||||
const saveValueChange = (event) => {
|
||||
const newValue = event.target.value;
|
||||
setDataRegistration({
|
||||
...dataRegistration,
|
||||
[event.target.id]: newValue,
|
||||
});
|
||||
};
|
||||
|
||||
const saveStoreRegistration = () => {
|
||||
if (fillingForm) {
|
||||
store.saveDataRegistration(
|
||||
Object.keys(dataRegistration).map((item) => ({
|
||||
key: `${item}`,
|
||||
value: dataRegistration[item],
|
||||
}))
|
||||
);
|
||||
navigate('/onboarding-3', { replace: true });
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (store.accountData.length === 0) return;
|
||||
setDataRegistration(
|
||||
store.accountData.reduce(
|
||||
(acc, item) => ({
|
||||
...acc,
|
||||
[item.key]: item.value,
|
||||
}),
|
||||
{}
|
||||
)
|
||||
);
|
||||
}, []);
|
||||
|
||||
function Onboarding2() {
|
||||
return (
|
||||
<main className="bg-white">
|
||||
|
||||
<div className="relative flex">
|
||||
|
||||
{/* Content */}
|
||||
<div className="w-full md:w-1/2">
|
||||
|
||||
<div className="min-h-screen h-full flex flex-col after:flex-1">
|
||||
|
||||
<div className="flex-1">
|
||||
|
||||
{/* Header */}
|
||||
<div className="flex items-center justify-between h-16 px-4 sm:px-6 lg:px-8">
|
||||
{/* Logo */}
|
||||
<Link className="block" to="/">
|
||||
<img alt='logo' src={Logo} width="89" height="32"/>
|
||||
<Link className="block" to="/dashboard">
|
||||
<img alt="logo" src={Logo} width="89" height="32" />
|
||||
</Link>
|
||||
<div className="text-sm">
|
||||
Have an account? <Link className="font-medium text-indigo-500 hover:text-indigo-600" to="/signin">Sign In</Link>
|
||||
Have an account?{' '}
|
||||
<Link
|
||||
className="font-medium text-indigo-500 hover:text-indigo-600"
|
||||
to="/signIn"
|
||||
>
|
||||
Sign In
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Progress bar */}
|
||||
<div className="px-4 pt-12 pb-8">
|
||||
<div className="px-4 pt-12 pb-[59px]">
|
||||
<div className="max-w-md mx-auto w-full">
|
||||
<div className="relative">
|
||||
<div className="absolute left-0 top-1/2 -mt-px w-full h-0.5 bg-slate-200" aria-hidden="true"></div>
|
||||
<div
|
||||
className="absolute left-0 top-1/2 -mt-px w-full h-0.5 bg-slate-200"
|
||||
aria-hidden="true"
|
||||
></div>
|
||||
<ul className="relative flex justify-between w-full">
|
||||
<li>
|
||||
<Link className="flex items-center justify-center w-6 h-6 rounded-full text-xs font-semibold bg-indigo-500 text-white" to="/onboarding-1">1</Link>
|
||||
<span
|
||||
className="flex items-center justify-center w-6 h-6 rounded-full text-xs font-semibold bg-indigo-500 text-white"
|
||||
to="/"
|
||||
>
|
||||
1
|
||||
</span>
|
||||
</li>
|
||||
<li>
|
||||
<Link className="flex items-center justify-center w-6 h-6 rounded-full text-xs font-semibold bg-indigo-500 text-white" to="/onboarding-2">2</Link>
|
||||
<span
|
||||
className="flex items-center justify-center w-6 h-6 rounded-full text-xs font-semibold bg-indigo-500 text-white"
|
||||
to="/onboarding-2"
|
||||
>
|
||||
2
|
||||
</span>
|
||||
</li>
|
||||
<li>
|
||||
<Link className="flex items-center justify-center w-6 h-6 rounded-full text-xs font-semibold bg-slate-100 text-slate-500" to="/onboarding-3">3</Link>
|
||||
<span
|
||||
className="flex items-center justify-center w-6 h-6 rounded-full text-xs font-semibold bg-slate-100 text-slate-500"
|
||||
to="/onboarding-3"
|
||||
>
|
||||
3
|
||||
</span>
|
||||
</li>
|
||||
<li>
|
||||
<Link className="flex items-center justify-center w-6 h-6 rounded-full text-xs font-semibold bg-slate-100 text-slate-500" to="/onboarding-4">4</Link>
|
||||
<span
|
||||
className="flex items-center justify-center w-6 h-6 rounded-full text-xs font-semibold bg-slate-100 text-slate-500"
|
||||
to="/onboarding-4"
|
||||
>
|
||||
4
|
||||
</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
@@ -54,64 +127,123 @@ function Onboarding2() {
|
||||
</div>
|
||||
|
||||
<div className="px-4 py-8">
|
||||
<div className="max-w-sm mx-auto">
|
||||
<h1 className="text-3xl text-slate-800 font-bold mb-6">Create your Account ✨</h1>
|
||||
<div className="max-w-[344px] mx-auto">
|
||||
<h1 className="text-3xl text-slate-800 font-bold mb-6">
|
||||
Create your Account ✨
|
||||
</h1>
|
||||
{/* Form */}
|
||||
<form>
|
||||
<div>
|
||||
<div className="space-y-4 mb-8">
|
||||
<div>
|
||||
<label className="block text-sm font-medium mb-1" htmlFor="email">Email Address <span className="text-rose-500">*</span></label>
|
||||
<input id="email" className="form-input w-full" type="email" />
|
||||
<label
|
||||
className="block text-sm font-medium mb-1"
|
||||
htmlFor="first_name"
|
||||
>
|
||||
First name <span className="text-rose-500">*</span>
|
||||
</label>
|
||||
<input
|
||||
id="firstname"
|
||||
onChange={(event) => saveValueChange(event)}
|
||||
className="form-input w-full"
|
||||
type="text"
|
||||
value={dataRegistration.firstname}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-sm font-medium mb-1" htmlFor="name">Full Name <span className="text-rose-500">*</span></label>
|
||||
<input id="name" 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="secondname"
|
||||
onChange={(event) => saveValueChange(event)}
|
||||
className="form-input w-full"
|
||||
type="text"
|
||||
value={dataRegistration.secondname}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-sm font-medium mb-1" htmlFor="role">Gender <span className="text-rose-500">*</span></label>
|
||||
<select id="role" className="form-select w-full">
|
||||
<label
|
||||
className="block text-sm font-medium mb-1"
|
||||
htmlFor="gender"
|
||||
>
|
||||
Gender <span className="text-rose-500">*</span>
|
||||
</label>
|
||||
<select
|
||||
id="gender"
|
||||
onChange={(event) => saveValueChange(event)}
|
||||
className="form-select w-full"
|
||||
value={dataRegistration.gender}
|
||||
>
|
||||
<option className="hidden"></option>
|
||||
<option>male</option>
|
||||
<option>feemale</option>
|
||||
<option>female</option>
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-sm font-medium mb-1" htmlFor="password">Date of birth <span className="text-rose-500">*</span></label>
|
||||
<input id="password" className="form-input w-full" type="password" 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"
|
||||
value={dataRegistration.birthdate}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center justify-between mt-6">
|
||||
<div className="mr-1">
|
||||
<label className="flex items-center">
|
||||
<input type="checkbox" className="form-checkbox" />
|
||||
<span className="text-sm ml-2">Email me about product news.</span>
|
||||
<span className="text-sm ml-2">
|
||||
Email me about product news.
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
<Link className="btn bg-indigo-500 hover:bg-indigo-600 text-white ml-3 whitespace-nowrap" to="/onboarding-3">Sign Up</Link>
|
||||
</div>
|
||||
</form>
|
||||
{/* Footer */}
|
||||
<div className="pt-5 mt-6 border-t border-slate-200">
|
||||
<div className="text-sm">
|
||||
Have an account? <Link className="font-medium text-indigo-500 hover:text-indigo-600" to="/onboarding-2">Sign In</Link>
|
||||
<button
|
||||
onClick={saveStoreRegistration}
|
||||
className="btn bg-indigo-500 hover:bg-indigo-600 text-white ml-3 whitespace-nowrap"
|
||||
>
|
||||
Sign Up
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
{/* Image */}
|
||||
<div className="hidden md:block absolute top-0 bottom-0 right-0 md:w-1/2" aria-hidden="true">
|
||||
<img className="object-cover object-center w-full h-full" src={OnboardingImage} width="760" height="1024" alt="Onboarding" />
|
||||
<img className="absolute top-1/4 left-0 transform -translate-x-1/2 ml-8 hidden lg:block" src={OnboardingDecoration} width="218" height="224" alt="Authentication decoration" />
|
||||
<div
|
||||
className="hidden md:block absolute top-0 bottom-0 right-0 md:w-1/2"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<img
|
||||
className="object-cover object-center w-full h-full"
|
||||
src={OnboardingImage}
|
||||
width="760"
|
||||
height="1024"
|
||||
alt="Onboarding"
|
||||
/>
|
||||
<img
|
||||
className="absolute top-1/4 left-0 transform -translate-x-1/2 ml-8 hidden lg:block"
|
||||
src={OnboardingDecoration}
|
||||
width="218"
|
||||
height="224"
|
||||
alt="Authentication decoration"
|
||||
/>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</main>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
export default Onboarding2;
|
||||
|
||||
@@ -1,30 +1,55 @@
|
||||
import React from 'react';
|
||||
import React, { useEffect } from 'react';
|
||||
import { observer } from 'mobx-react-lite';
|
||||
import { Link } from 'react-router-dom';
|
||||
import {generateSvgAvatar} from "../images/GenerateOnboardingSvg/GenerateSvg";
|
||||
import Logo from "../images/logo.png";
|
||||
import { generateSvgAvatar } from '../images/GenerateOnboardingSvg/GenerateSvg';
|
||||
import Logo from '../images/logo.png';
|
||||
import { store } from '../store/store';
|
||||
|
||||
const Onboarding3 = observer(() => {
|
||||
useEffect(() => {
|
||||
store.generatePassPhrase();
|
||||
}, []);
|
||||
|
||||
const generatePassPhrase = () => {
|
||||
store.generatePassPhrase();
|
||||
};
|
||||
|
||||
const savePassPhraseInStore = (copiedPhrase) => {
|
||||
if (copiedPhrase.split(' ').length === 12) {
|
||||
store.savePastPassPhrase(copiedPhrase.trim());
|
||||
}
|
||||
};
|
||||
|
||||
const pastePassPhrase = () => {
|
||||
navigator.clipboard.readText().then((res) => savePassPhraseInStore(res));
|
||||
};
|
||||
|
||||
const convertPassPhraseToArray = () =>
|
||||
store.passPhrase
|
||||
.split(' ')
|
||||
.map((item, index) => ({ str: item, id: index }));
|
||||
|
||||
function Onboarding3() {
|
||||
const arrayBadges = ['judge', 'jelly', 'wasp', 'true', 'clog', 'forward', 'talent', 'ozone', 'belive', 'fresh', 'bulk', 'hobby']
|
||||
return (
|
||||
<main className="bg-white">
|
||||
|
||||
<div className="relative flex">
|
||||
|
||||
{/* Content */}
|
||||
<div className="w-full md:w-1/2">
|
||||
|
||||
<div className="min-h-screen h-full flex flex-col after:flex-1">
|
||||
|
||||
<div className="flex-1">
|
||||
|
||||
{/* Header */}
|
||||
<div className="flex items-center justify-between h-16 px-4 sm:px-6 lg:px-8">
|
||||
{/* Logo */}
|
||||
<Link className="block" to="/">
|
||||
<img alt='logo' src={Logo} width="89" height="32"/>
|
||||
<Link className="block" to="/dashboard">
|
||||
<img alt="logo" src={Logo} width="89" height="32" />
|
||||
</Link>
|
||||
<div className="text-sm">
|
||||
Have an account? <Link className="font-medium text-indigo-500 hover:text-indigo-600" to="/signin">Sign In</Link>
|
||||
Have an account?{' '}
|
||||
<Link
|
||||
className="font-medium text-indigo-500 hover:text-indigo-600"
|
||||
to="/signIn"
|
||||
>
|
||||
Sign In
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -32,19 +57,42 @@ function Onboarding3() {
|
||||
<div className="px-4 pt-12 pb-8">
|
||||
<div className="max-w-md mx-auto w-full">
|
||||
<div className="relative">
|
||||
<div className="absolute left-0 top-1/2 -mt-px w-full h-0.5 bg-slate-200" aria-hidden="true"></div>
|
||||
<div
|
||||
className="absolute left-0 top-1/2 -mt-px w-full h-0.5 bg-slate-200"
|
||||
aria-hidden="true"
|
||||
></div>
|
||||
<ul className="relative flex justify-between w-full">
|
||||
<li>
|
||||
<Link className="flex items-center justify-center w-6 h-6 rounded-full text-xs font-semibold bg-indigo-500 text-white" to="/onboarding-1">1</Link>
|
||||
<span
|
||||
className="flex items-center justify-center w-6 h-6 rounded-full text-xs font-semibold bg-indigo-500 text-white"
|
||||
to="/"
|
||||
>
|
||||
1
|
||||
</span>
|
||||
</li>
|
||||
<li>
|
||||
<Link className="flex items-center justify-center w-6 h-6 rounded-full text-xs font-semibold bg-indigo-500 text-white" to="/onboarding-2">2</Link>
|
||||
<span
|
||||
className="flex items-center justify-center w-6 h-6 rounded-full text-xs font-semibold bg-indigo-500 text-white"
|
||||
to="/onboarding-2"
|
||||
>
|
||||
2
|
||||
</span>
|
||||
</li>
|
||||
<li>
|
||||
<Link className="flex items-center justify-center w-6 h-6 rounded-full text-xs font-semibold bg-indigo-500 text-white" to="/onboarding-3">3</Link>
|
||||
<span
|
||||
className="flex items-center justify-center w-6 h-6 rounded-full text-xs font-semibold bg-indigo-500 text-white"
|
||||
to="/onboarding-3"
|
||||
>
|
||||
3
|
||||
</span>
|
||||
</li>
|
||||
<li>
|
||||
<Link className="flex items-center justify-center w-6 h-6 rounded-full text-xs font-semibold bg-slate-100 text-slate-500" to="/onboarding-4">4</Link>
|
||||
<span
|
||||
className="flex items-center justify-center w-6 h-6 rounded-full text-xs font-semibold bg-slate-100 text-slate-500"
|
||||
to="/onboarding-4"
|
||||
>
|
||||
4
|
||||
</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
@@ -54,58 +102,96 @@ function Onboarding3() {
|
||||
|
||||
<div className="px-4 mt-20 py-8">
|
||||
<div className="max-w-fit mx-auto flex flex-col gap-y-36">
|
||||
|
||||
<div className="gap-0.5">
|
||||
<h1 className="text-3xl text-slate-800 font-bold mb-12">Company information ✨</h1>
|
||||
<h1 className="text-3xl text-slate-800 font-bold mb-12">
|
||||
Company information ✨
|
||||
</h1>
|
||||
{/* htmlForm */}
|
||||
<div className="grid grid-cols-4 gap-2.5 mb-14">
|
||||
{arrayBadges.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>
|
||||
<div className="grid grid-cols-4 gap-y-2.5 gap-[18px] mb-14">
|
||||
{convertPassPhraseToArray().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 justify-center gap-x-5">
|
||||
<button 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>
|
||||
<div className="flex pl-7 gap-x-5">
|
||||
<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 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"/>
|
||||
<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"
|
||||
/>
|
||||
</svg>
|
||||
<span className="ml-2">Generate</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center justify-between">
|
||||
<Link className="text-sm underline hover:no-underline" to="/onboarding-2"><- Back</Link>
|
||||
<Link className="btn bg-indigo-500 hover:bg-indigo-600 text-white ml-auto" to="/onboarding-4">Next Step -></Link>
|
||||
<Link
|
||||
className="text-sm underline hover:no-underline"
|
||||
to="/onboarding-2"
|
||||
>
|
||||
<- Back
|
||||
</Link>
|
||||
<button className="btn bg-indigo-500 hover:bg-indigo-600 text-white ml-auto">
|
||||
<Link to="/onboarding-4">Next Step -></Link>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
{/* 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 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(store.pubKey)}
|
||||
width="493px"
|
||||
height="493px"
|
||||
alt="Onboarding"
|
||||
/>
|
||||
<span className="text-sm">Your generated Digital ID</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</main>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
export default Onboarding3;
|
||||
|
||||
@@ -1,49 +1,97 @@
|
||||
import React 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 { generateSvgAvatar } from '../images/GenerateOnboardingSvg/GenerateSvg';
|
||||
import Logo from '../images/logo.png';
|
||||
import { observer } from 'mobx-react-lite';
|
||||
import { store } from '../store/store';
|
||||
|
||||
const Onboarding4 = observer(() => {
|
||||
const [checkBoxesSelected, setCheckBoxesSelected] = useState([]);
|
||||
|
||||
function createAccount() {
|
||||
if (checkBoxesSelected.length === 2) {
|
||||
store.pushAccountData();
|
||||
sessionStorage.setItem('passPhrase', store.passPhrase);
|
||||
store.clearDataRegistration();
|
||||
}
|
||||
}
|
||||
|
||||
function saveCheckBoxesValues(e) {
|
||||
const { id, checked } = e.target;
|
||||
setCheckBoxesSelected([...checkBoxesSelected, id]);
|
||||
if (!checked) {
|
||||
setCheckBoxesSelected(checkBoxesSelected.filter((item) => item !== id));
|
||||
}
|
||||
}
|
||||
|
||||
const firstNameAccount =
|
||||
store.accountData.length &&
|
||||
store.accountData.find((item) => item.key === 'firstname').value;
|
||||
|
||||
function Onboarding4() {
|
||||
return (
|
||||
<main className="bg-white">
|
||||
|
||||
<div className="relative flex">
|
||||
|
||||
{/* Content */}
|
||||
<div className="w-full md:w-1/2">
|
||||
|
||||
<div className="min-h-screen h-full flex flex-col after:flex-1">
|
||||
|
||||
<div className="flex-1">
|
||||
|
||||
{/* Header */}
|
||||
<div className="flex items-center justify-between h-16 px-4 sm:px-6 lg:px-8">
|
||||
{/* Logo */}
|
||||
<Link className="block" to="/">
|
||||
<img alt='logo' src={Logo} width="89" height="32"/>
|
||||
<Link className="block" to="/dashboard">
|
||||
<img alt="logo" src={Logo} width="89" height="32" />
|
||||
</Link>
|
||||
<div className="text-sm">
|
||||
Have an account? <Link className="font-medium text-indigo-500 hover:text-indigo-600" to="/signin">Sign In</Link>
|
||||
Have an account?{' '}
|
||||
<Link
|
||||
className="font-medium text-indigo-500 hover:text-indigo-600"
|
||||
to="/signIn"
|
||||
>
|
||||
Sign In
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Progress bar */}
|
||||
<div className="px-4 pt-12 pb-8">
|
||||
<div className="px-4 pt-12 pb-[85px]">
|
||||
<div className="max-w-md mx-auto w-full">
|
||||
<div className="relative">
|
||||
<div className="absolute left-0 top-1/2 -mt-px w-full h-0.5 bg-slate-200" aria-hidden="true"></div>
|
||||
<div
|
||||
className="absolute left-0 top-1/2 -mt-px w-full h-0.5 bg-slate-200"
|
||||
aria-hidden="true"
|
||||
></div>
|
||||
<ul className="relative flex justify-between w-full">
|
||||
<li>
|
||||
<Link className="flex items-center justify-center w-6 h-6 rounded-full text-xs font-semibold bg-indigo-500 text-white" to="/onboarding-1">1</Link>
|
||||
<span
|
||||
className="flex items-center justify-center w-6 h-6 rounded-full text-xs font-semibold bg-indigo-500 text-white"
|
||||
to="/"
|
||||
>
|
||||
1
|
||||
</span>
|
||||
</li>
|
||||
<li>
|
||||
<Link className="flex items-center justify-center w-6 h-6 rounded-full text-xs font-semibold bg-indigo-500 text-white" to="/onboarding-2">2</Link>
|
||||
<span
|
||||
className="flex items-center justify-center w-6 h-6 rounded-full text-xs font-semibold bg-indigo-500 text-white"
|
||||
to="/onboarding-2"
|
||||
>
|
||||
2
|
||||
</span>
|
||||
</li>
|
||||
<li>
|
||||
<Link className="flex items-center justify-center w-6 h-6 rounded-full text-xs font-semibold bg-indigo-500 text-white" to="/onboarding-3">3</Link>
|
||||
<span
|
||||
className="flex items-center justify-center w-6 h-6 rounded-full text-xs font-semibold bg-indigo-500 text-white"
|
||||
to="/onboarding-3"
|
||||
>
|
||||
3
|
||||
</span>
|
||||
</li>
|
||||
<li>
|
||||
<Link className="flex items-center justify-center w-6 h-6 rounded-full text-xs font-semibold bg-indigo-500 text-white" to="/onboarding-4">4</Link>
|
||||
<span
|
||||
className="flex items-center justify-center w-6 h-6 rounded-full text-xs font-semibold bg-indigo-500 text-white"
|
||||
to="/onboarding-4"
|
||||
>
|
||||
4
|
||||
</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
@@ -53,50 +101,100 @@ function Onboarding4() {
|
||||
|
||||
<div className="px-4 mt-40 py-8">
|
||||
<div className=" flex flex-col items-center gap-20 max-w-md mx-auto">
|
||||
|
||||
<div className="text-center">
|
||||
<svg className="inline-flex w-16 h-16 fill-current mb-6" viewBox="0 0 64 64">
|
||||
<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
|
||||
className="inline-flex w-16 h-16 fill-current mb-6"
|
||||
viewBox="0 0 64 64"
|
||||
>
|
||||
<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, Ivan 🙌</h1>
|
||||
<Link className="btn bg-indigo-500 hover:bg-indigo-600 text-white" to="/">Go To Profile -></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 &&
|
||||
'/digitalId/profile-id'
|
||||
}
|
||||
>
|
||||
Go To Profile ->
|
||||
</Link>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center justify-between mt-6">
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="mr-1">
|
||||
<label className="flex items-center">
|
||||
<input type="checkbox" className="form-checkbox" />
|
||||
<span className="text-sm ml-2">I understand that Idntty cannot recover pass phrase</span>
|
||||
<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">
|
||||
<Link className="font-medium text-indigo-500 hover:text-indigo-600" to="/">I store my pharse</Link> very carefuly
|
||||
I{' '}
|
||||
<Link
|
||||
className="text-indigo-500 hover:text-indigo-600 underline"
|
||||
to="/"
|
||||
>
|
||||
store my pharse
|
||||
</Link>{' '}
|
||||
very carefuly
|
||||
</div>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
{/* 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 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(store.pubKey)}
|
||||
width="493px"
|
||||
height="493px"
|
||||
alt="Onboarding"
|
||||
/>
|
||||
<span className="text-sm">Your generated Digital ID</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</main>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
export default Onboarding4;
|
||||
|
||||
@@ -1,71 +1,78 @@
|
||||
import React from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
import AuthImage from '../images/auth-image.jpg';
|
||||
import AuthDecoration from '../images/auth-decoration.png';
|
||||
import Logo from '../images/logo.png';
|
||||
|
||||
function ResetPassword() {
|
||||
return (
|
||||
<main className="bg-white">
|
||||
|
||||
<div className="relative md:flex">
|
||||
|
||||
{/* Content */}
|
||||
<div className="md:w-1/2">
|
||||
<div className="min-h-screen h-full flex flex-col after:flex-1">
|
||||
|
||||
{/* Header */}
|
||||
<div className="flex-1">
|
||||
<div className="flex items-center justify-between h-16 px-4 sm:px-6 lg:px-8">
|
||||
{/* Logo */}
|
||||
<Link className="block" to="/">
|
||||
<svg width="32" height="32" viewBox="0 0 32 32">
|
||||
<defs>
|
||||
<linearGradient x1="28.538%" y1="20.229%" x2="100%" y2="108.156%" id="logo-a">
|
||||
<stop stopColor="#A5B4FC" stopOpacity="0" offset="0%" />
|
||||
<stop stopColor="#A5B4FC" offset="100%" />
|
||||
</linearGradient>
|
||||
<linearGradient x1="88.638%" y1="29.267%" x2="22.42%" y2="100%" id="logo-b">
|
||||
<stop stopColor="#38BDF8" stopOpacity="0" offset="0%" />
|
||||
<stop stopColor="#38BDF8" offset="100%" />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<rect fill="#6366F1" width="32" height="32" rx="16" />
|
||||
<path d="M18.277.16C26.035 1.267 32 7.938 32 16c0 8.837-7.163 16-16 16a15.937 15.937 0 01-10.426-3.863L18.277.161z" fill="#4F46E5" />
|
||||
<path d="M7.404 2.503l18.339 26.19A15.93 15.93 0 0116 32C7.163 32 0 24.837 0 16 0 10.327 2.952 5.344 7.404 2.503z" fill="url(#logo-a)" />
|
||||
<path d="M2.223 24.14L29.777 7.86A15.926 15.926 0 0132 16c0 8.837-7.163 16-16 16-5.864 0-10.991-3.154-13.777-7.86z" fill="url(#logo-b)" />
|
||||
</svg>
|
||||
<Link className="block" to="/dashboard">
|
||||
<img alt="logo" src={Logo} width="89" height="32" />
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="max-w-sm mx-auto px-4 py-8">
|
||||
<h1 className="text-3xl text-slate-800 font-bold mb-6">Reset your Password ✨</h1>
|
||||
<h1 className="text-3xl text-slate-800 font-bold mb-6">
|
||||
Reset your Password ✨
|
||||
</h1>
|
||||
{/* Form */}
|
||||
<form>
|
||||
<div>
|
||||
<div className="space-y-4">
|
||||
<div>
|
||||
<label className="block text-sm font-medium mb-1" htmlFor="email">Email Address <span className="text-rose-500">*</span></label>
|
||||
<input id="email" className="form-input w-full" type="email" />
|
||||
<label
|
||||
className="block text-sm font-medium mb-1"
|
||||
htmlFor="email"
|
||||
>
|
||||
Email Address <span className="text-rose-500">*</span>
|
||||
</label>
|
||||
<input
|
||||
id="email"
|
||||
className="form-input w-full"
|
||||
type="email"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex justify-end mt-6">
|
||||
<button className="btn bg-indigo-500 hover:bg-indigo-600 text-white whitespace-nowrap">Send Reset Link</button>
|
||||
<button className="btn bg-indigo-500 hover:bg-indigo-600 text-white whitespace-nowrap">
|
||||
Send Reset Link
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Image */}
|
||||
<div className="hidden md:block absolute top-0 bottom-0 right-0 md:w-1/2" aria-hidden="true">
|
||||
<img className="object-cover object-center w-full h-full" src={AuthImage} width="760" height="1024" alt="Authentication" />
|
||||
<img className="absolute top-1/4 left-0 transform -translate-x-1/2 ml-8 hidden lg:block" src={AuthDecoration} width="218" height="224" alt="Authentication decoration" />
|
||||
<div
|
||||
className="hidden md:block absolute top-0 bottom-0 right-0 md:w-1/2"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<img
|
||||
className="object-cover object-center w-full h-full"
|
||||
src={AuthImage}
|
||||
width="760"
|
||||
height="1024"
|
||||
alt="Authentication"
|
||||
/>
|
||||
<img
|
||||
className="absolute top-1/4 left-0 transform -translate-x-1/2 ml-8 hidden lg:block"
|
||||
src={AuthDecoration}
|
||||
width="218"
|
||||
height="224"
|
||||
alt="Authentication decoration"
|
||||
/>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</main>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,103 +1,153 @@
|
||||
import React from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
import {generateSvgAvatar} from "../images/GenerateOnboardingSvg/GenerateSvg";
|
||||
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 SharedDataRoadMap from "../partials/shareddata/SharedDataRoadmap";
|
||||
import React, { useEffect, useMemo, useState } from 'react';
|
||||
import { Link, Navigate, useParams } from 'react-router-dom';
|
||||
import { generateSvgAvatar } from '../images/GenerateOnboardingSvg/GenerateSvg';
|
||||
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 SharedDataRoadMap from '../partials/sharedData/SharedDataRoadmap';
|
||||
import { store } from '../store/store';
|
||||
import { fetchWrapper } from '../shared/fetchWrapper';
|
||||
import { cryptography } from '@liskhq/lisk-client';
|
||||
import { generateTransaction } from '../utils/Utils';
|
||||
|
||||
function SharedData() {
|
||||
const [encryptedData, setEncryptedData] = useState([]);
|
||||
const [hasError, setHasError] = useState(false);
|
||||
|
||||
const sharedDataItems = {
|
||||
data: localStorage.getItem('digitalId'),
|
||||
items: [
|
||||
{
|
||||
dataShared: localStorage.getItem('digitalId'),
|
||||
id: '923',
|
||||
text: 'United Kindom',
|
||||
typeItem: 'Residence',
|
||||
usersImges: [
|
||||
{
|
||||
size: 32,
|
||||
img: User06,
|
||||
imgId: "90"
|
||||
},
|
||||
{
|
||||
size: 32,
|
||||
img: User08,
|
||||
imgId: "93"
|
||||
},
|
||||
{
|
||||
size: 32,
|
||||
img: User09,
|
||||
imgId: "89"
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
dataShared: localStorage.getItem('digitalId'),
|
||||
id: '401',
|
||||
text: 'A123B3143',
|
||||
typeItem: 'Document ID',
|
||||
usersImges: [
|
||||
{
|
||||
size: 32,
|
||||
img: User06,
|
||||
imgId: "67"
|
||||
},
|
||||
{
|
||||
size: 32,
|
||||
img: User08,
|
||||
imgId: "71"
|
||||
},
|
||||
],
|
||||
},
|
||||
]
|
||||
};
|
||||
const { id } = useParams();
|
||||
|
||||
const [address, pubKey] = id.split(':');
|
||||
|
||||
const passPhrase = sessionStorage.getItem('passPhrase');
|
||||
|
||||
useEffect(() => {
|
||||
fetchWrapper
|
||||
.get(`data/shared/${id}`)
|
||||
.then((res) => setEncryptedData(res.data ?? []))
|
||||
.catch((err) => console.log(err));
|
||||
}, [id]);
|
||||
|
||||
const decryptedData = useMemo(() => {
|
||||
return encryptedData.map((item) => {
|
||||
let seed, value, hash;
|
||||
try {
|
||||
[seed, value] = cryptography
|
||||
.decryptMessageWithPassphrase(
|
||||
item.value,
|
||||
item.value_nonce,
|
||||
passPhrase,
|
||||
Buffer.from(pubKey, 'hex')
|
||||
)
|
||||
.split(':');
|
||||
hash = cryptography
|
||||
.hash(
|
||||
Buffer.concat([
|
||||
Buffer.from(seed, 'utf8'),
|
||||
cryptography.hash(value, 'utf8'),
|
||||
])
|
||||
)
|
||||
.toString('hex');
|
||||
} catch (err) {
|
||||
setHasError(true);
|
||||
console.log(err);
|
||||
} finally {
|
||||
return {
|
||||
seed,
|
||||
value,
|
||||
hash,
|
||||
label: item.label,
|
||||
};
|
||||
}
|
||||
});
|
||||
}, [encryptedData]);
|
||||
|
||||
const validateAccountData = () => {
|
||||
const builder = generateTransaction(
|
||||
BigInt(store.accountInfo?.sequence?.nonce || 0),
|
||||
store.pubKey,
|
||||
store.nodeInfo.networkIdentifier,
|
||||
store.passPhrase,
|
||||
store.nodeInfo?.genesisConfig?.minFeePerByte,
|
||||
store.nodeInfo?.genesisConfig?.baseFees
|
||||
);
|
||||
|
||||
const signedTx = builder.validate(
|
||||
decryptedData.map((e) => ({
|
||||
label: e.label,
|
||||
value: Buffer.from(e.hash, 'hex'),
|
||||
})),
|
||||
address
|
||||
);
|
||||
|
||||
if (signedTx) {
|
||||
fetchWrapper
|
||||
.post('transactions', {}, signedTx)
|
||||
.catch((err) => console.log(err));
|
||||
}
|
||||
};
|
||||
|
||||
if (!passPhrase) return <Navigate to="/" replace={true} />;
|
||||
|
||||
function saveDigitalId() {
|
||||
localStorage.setItem('svgAvatar', generateSvgAvatar())
|
||||
}
|
||||
return (
|
||||
<main className="bg-white">
|
||||
|
||||
<div className="relative flex">
|
||||
|
||||
{/* Content */}
|
||||
<div className="w-full md:w-1/2">
|
||||
|
||||
<div className="min-h-screen h-full flex flex-col after:flex-1">
|
||||
|
||||
<div className="px-4 mt-16 py-9">
|
||||
<div className=" flex flex-col max-w-md mx-auto">
|
||||
<h1 className="text-3xl text-slate-800 font-bold mb-8">Shared data ✨</h1>
|
||||
<h1 className="text-3xl text-slate-800 font-bold mb-8">
|
||||
Shared data ✨
|
||||
</h1>
|
||||
<ul>
|
||||
{sharedDataItems.items.map(item => {
|
||||
return(
|
||||
<li key={item.id}>
|
||||
<SharedDataRoadMap data={item}/>
|
||||
</li>
|
||||
);
|
||||
})}
|
||||
{!hasError &&
|
||||
decryptedData.map((item) => (
|
||||
<li key={item.label}>
|
||||
<SharedDataRoadMap data={item} />
|
||||
</li>
|
||||
))}
|
||||
{hasError &&
|
||||
encryptedData.map((item) => (
|
||||
<li key={item.label}>
|
||||
<SharedDataRoadMap data={item} />
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
{!hasError && (
|
||||
<button
|
||||
className="mt-12 btn bg-indigo-500 hover:bg-indigo-600 text-white"
|
||||
onClick={validateAccountData}
|
||||
>
|
||||
Validate data
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
{/* 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 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" />
|
||||
<span className="text-sm">{sharedDataItems.data}</span>
|
||||
<Link onClick={()=>saveDigitalId()} className="mt-12 btn bg-indigo-500 hover:bg-indigo-600 text-white" to="/">Get my digital ID</Link>
|
||||
<img
|
||||
className="object-cover object-center"
|
||||
src={generateSvgAvatar(store.pubKey)}
|
||||
width="493px"
|
||||
height="493px"
|
||||
alt="Onboarding"
|
||||
/>
|
||||
<Link
|
||||
className="mt-12 btn bg-indigo-500 hover:bg-indigo-600 text-white"
|
||||
to="/"
|
||||
>
|
||||
Get my digital ID
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</main>
|
||||
);
|
||||
}
|
||||
|
||||
124
src/pages/SignIn.jsx
Normal file
@@ -0,0 +1,124 @@
|
||||
import React, { useState } from 'react';
|
||||
import { observer } from 'mobx-react-lite';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { generateSvgAvatar } from '../images/GenerateOnboardingSvg/GenerateSvg';
|
||||
import Logo from '../images/logo.png';
|
||||
import { store } from '../store/store';
|
||||
|
||||
const SignIn = observer(() => {
|
||||
const [passPhrase, setPassPhrase] = useState('- - - - - - - - - - - -');
|
||||
const [addedPassPhrase, setAddedPassPhrase] = useState(false);
|
||||
|
||||
function savePassPhrase(copiedPhrase) {
|
||||
if (copiedPhrase.split(' ').length === 12) {
|
||||
store.savePastPassPhrase(copiedPhrase.trim());
|
||||
setPassPhrase(store.passPhrase);
|
||||
setAddedPassPhrase(true);
|
||||
}
|
||||
}
|
||||
|
||||
function convertPassPhraseToArray() {
|
||||
return passPhrase
|
||||
.split(' ')
|
||||
.map((item, index) => ({ str: item, id: index }));
|
||||
}
|
||||
|
||||
function pastePassPhrase() {
|
||||
navigator.clipboard.readText().then((res) => savePassPhrase(res));
|
||||
}
|
||||
|
||||
return (
|
||||
<main className="bg-white">
|
||||
<div className="relative flex">
|
||||
{/* Content */}
|
||||
<div className="w-full md:w-1/2">
|
||||
<div className="min-h-screen h-full flex flex-col after:flex-1">
|
||||
<div className="flex-1">
|
||||
{/* Header */}
|
||||
<div className="flex items-center justify-between h-16 px-4 sm:px-6 lg:px-8">
|
||||
{/* Logo */}
|
||||
<Link className="block" to="/">
|
||||
<img alt="logo" src={Logo} width="89" height="32" />
|
||||
</Link>
|
||||
<div className="text-sm">
|
||||
Have not an account?{' '}
|
||||
<Link
|
||||
className="font-medium text-indigo-500 hover:text-indigo-600"
|
||||
to="/"
|
||||
>
|
||||
Sign Up
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="px-4 mt-20 py-8">
|
||||
<div className="max-w-fit mx-auto flex flex-col gap-y-36">
|
||||
<div>
|
||||
<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">
|
||||
{convertPassPhraseToArray().map((tag) => (
|
||||
<button
|
||||
key={tag.id}
|
||||
className="min-w-[93px] min-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
|
||||
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>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center justify-between">
|
||||
<button className="btn bg-indigo-500 hover:bg-indigo-600 text-white ml-auto">
|
||||
<Link to={addedPassPhrase && '/digitalId/profile-id'}>
|
||||
Go To Profile ->
|
||||
</Link>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 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">
|
||||
<div
|
||||
className={`${
|
||||
addedPassPhrase || 'opacity-0'
|
||||
} w-[493px] h-[493px]`}
|
||||
>
|
||||
<img
|
||||
className="object-cover object-center"
|
||||
alt=""
|
||||
src={generateSvgAvatar(store.pubKey)}
|
||||
/>
|
||||
</div>
|
||||
<span className="text-sm">Your Digital ID</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
);
|
||||
});
|
||||
|
||||
export default SignIn;
|
||||
@@ -1,100 +0,0 @@
|
||||
import React, { useEffect } from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
import AuthImage from '../images/auth-image.jpg';
|
||||
import AuthDecoration from '../images/auth-decoration.png';
|
||||
|
||||
function Signin() {
|
||||
useEffect(() => {
|
||||
localStorage.setItem('svgKey', '')
|
||||
}, [])
|
||||
return (
|
||||
<main className="bg-white">
|
||||
|
||||
<div className="relative md:flex">
|
||||
|
||||
{/* Content */}
|
||||
<div className="md:w-1/2">
|
||||
<div className="min-h-screen h-full flex flex-col after:flex-1">
|
||||
|
||||
{/* Header */}
|
||||
<div className="flex-1">
|
||||
<div className="flex items-center justify-between h-16 px-4 sm:px-6 lg:px-8">
|
||||
{/* Logo */}
|
||||
<Link className="block" to="/">
|
||||
<svg width="32" height="32" viewBox="0 0 32 32">
|
||||
<defs>
|
||||
<linearGradient x1="28.538%" y1="20.229%" x2="100%" y2="108.156%" id="logo-a">
|
||||
<stop stopColor="#A5B4FC" stopOpacity="0" offset="0%" />
|
||||
<stop stopColor="#A5B4FC" offset="100%" />
|
||||
</linearGradient>
|
||||
<linearGradient x1="88.638%" y1="29.267%" x2="22.42%" y2="100%" id="logo-b">
|
||||
<stop stopColor="#38BDF8" stopOpacity="0" offset="0%" />
|
||||
<stop stopColor="#38BDF8" offset="100%" />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<rect fill="#6366F1" width="32" height="32" rx="16" />
|
||||
<path d="M18.277.16C26.035 1.267 32 7.938 32 16c0 8.837-7.163 16-16 16a15.937 15.937 0 01-10.426-3.863L18.277.161z" fill="#4F46E5" />
|
||||
<path d="M7.404 2.503l18.339 26.19A15.93 15.93 0 0116 32C7.163 32 0 24.837 0 16 0 10.327 2.952 5.344 7.404 2.503z" fill="url(#logo-a)" />
|
||||
<path d="M2.223 24.14L29.777 7.86A15.926 15.926 0 0132 16c0 8.837-7.163 16-16 16-5.864 0-10.991-3.154-13.777-7.86z" fill="url(#logo-b)" />
|
||||
</svg>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="max-w-sm mx-auto px-4 py-8">
|
||||
<h1 className="text-3xl text-slate-800 font-bold mb-6">Welcome back! ✨</h1>
|
||||
{/* Form */}
|
||||
<form>
|
||||
<div className="space-y-4">
|
||||
<div>
|
||||
<label className="block text-sm font-medium mb-1" htmlFor="email">Email Address</label>
|
||||
<input id="email" className="form-input w-full" type="email" />
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-sm font-medium mb-1" htmlFor="password">Password</label>
|
||||
<input id="password" className="form-input w-full" type="password" autoComplete="on" />
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center justify-between mt-6">
|
||||
<div className="mr-1">
|
||||
<Link className="text-sm underline hover:no-underline" to="/reset-password">Forgot Password?</Link>
|
||||
</div>
|
||||
<Link className="btn bg-indigo-500 hover:bg-indigo-600 text-white ml-3" to="/">Sign In</Link>
|
||||
</div>
|
||||
</form>
|
||||
{/* Footer */}
|
||||
<div className="pt-5 mt-6 border-t border-slate-200">
|
||||
<div className="text-sm">
|
||||
Don’t you have an account? <Link className="font-medium text-indigo-500 hover:text-indigo-600" to="/signup">Sign Up</Link>
|
||||
</div>
|
||||
{/* Warning */}
|
||||
<div className="mt-5">
|
||||
<div className="bg-amber-100 text-amber-600 px-3 py-2 rounded">
|
||||
<svg className="inline w-3 h-3 shrink-0 fill-current mr-2" viewBox="0 0 12 12">
|
||||
<path d="M10.28 1.28L3.989 7.575 1.695 5.28A1 1 0 00.28 6.695l3 3a1 1 0 001.414 0l7-7A1 1 0 0010.28 1.28z" />
|
||||
</svg>
|
||||
<span className="text-sm">
|
||||
To support you during the pandemic super pro features are free until March 31st.
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Image */}
|
||||
<div className="hidden md:block absolute top-0 bottom-0 right-0 md:w-1/2" aria-hidden="true">
|
||||
<img className="object-cover object-center w-full h-full" src={AuthImage} width="760" height="1024" alt="Authentication" />
|
||||
<img className="absolute top-1/4 left-0 transform -translate-x-1/2 ml-8 hidden lg:block" src={AuthDecoration} width="218" height="224" alt="Authentication decoration" />
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</main>
|
||||
);
|
||||
}
|
||||
|
||||
export default Signin;
|
||||
@@ -1,101 +0,0 @@
|
||||
import React from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
import AuthImage from '../images/auth-image.jpg';
|
||||
import AuthDecoration from '../images/auth-decoration.png';
|
||||
|
||||
function Signup() {
|
||||
return (
|
||||
<main className="bg-white">
|
||||
|
||||
<div className="relative md:flex">
|
||||
|
||||
{/* Content */}
|
||||
<div className="md:w-1/2">
|
||||
<div className="min-h-screen h-full flex flex-col after:flex-1">
|
||||
|
||||
{/* Header */}
|
||||
<div className="flex-1">
|
||||
<div className="flex items-center justify-between h-16 px-4 sm:px-6 lg:px-8">
|
||||
{/* Logo */}
|
||||
<Link className="block" to="/">
|
||||
<svg width="32" height="32" viewBox="0 0 32 32">
|
||||
<defs>
|
||||
<linearGradient x1="28.538%" y1="20.229%" x2="100%" y2="108.156%" id="logo-a">
|
||||
<stop stopColor="#A5B4FC" stopOpacity="0" offset="0%" />
|
||||
<stop stopColor="#A5B4FC" offset="100%" />
|
||||
</linearGradient>
|
||||
<linearGradient x1="88.638%" y1="29.267%" x2="22.42%" y2="100%" id="logo-b">
|
||||
<stop stopColor="#38BDF8" stopOpacity="0" offset="0%" />
|
||||
<stop stopColor="#38BDF8" offset="100%" />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<rect fill="#6366F1" width="32" height="32" rx="16" />
|
||||
<path d="M18.277.16C26.035 1.267 32 7.938 32 16c0 8.837-7.163 16-16 16a15.937 15.937 0 01-10.426-3.863L18.277.161z" fill="#4F46E5" />
|
||||
<path d="M7.404 2.503l18.339 26.19A15.93 15.93 0 0116 32C7.163 32 0 24.837 0 16 0 10.327 2.952 5.344 7.404 2.503z" fill="url(#logo-a)" />
|
||||
<path d="M2.223 24.14L29.777 7.86A15.926 15.926 0 0132 16c0 8.837-7.163 16-16 16-5.864 0-10.991-3.154-13.777-7.86z" fill="url(#logo-b)" />
|
||||
</svg>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="max-w-sm mx-auto px-4 py-8">
|
||||
<h1 className="text-3xl text-slate-800 font-bold mb-6">Create your Account ✨</h1>
|
||||
{/* Form */}
|
||||
<form>
|
||||
<div className="space-y-4">
|
||||
<div>
|
||||
<label className="block text-sm font-medium mb-1" htmlFor="email">Email Address <span className="text-rose-500">*</span></label>
|
||||
<input id="email" className="form-input w-full" type="email" />
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-sm font-medium mb-1" htmlFor="name">Full Name <span className="text-rose-500">*</span></label>
|
||||
<input id="name" className="form-input w-full" type="text" />
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-sm font-medium mb-1" htmlFor="role">Your Role <span className="text-rose-500">*</span></label>
|
||||
<select id="role" className="form-select w-full">
|
||||
<option>Designer</option>
|
||||
<option>Developer</option>
|
||||
<option>Accountant</option>
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-sm font-medium mb-1" htmlFor="password">Password</label>
|
||||
<input id="password" className="form-input w-full" type="password" autoComplete="on" />
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center justify-between mt-6">
|
||||
<div className="mr-1">
|
||||
<label className="flex items-center">
|
||||
<input type="checkbox" className="form-checkbox" />
|
||||
<span className="text-sm ml-2">Email me about product news.</span>
|
||||
</label>
|
||||
</div>
|
||||
<Link className="btn bg-indigo-500 hover:bg-indigo-600 text-white ml-3 whitespace-nowrap" to="/">Sign Up</Link>
|
||||
</div>
|
||||
</form>
|
||||
{/* Footer */}
|
||||
<div className="pt-5 mt-6 border-t border-slate-200">
|
||||
<div className="text-sm">
|
||||
Have an account? <Link className="font-medium text-indigo-500 hover:text-indigo-600" to="/signin">Sign In</Link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Image */}
|
||||
<div className="hidden md:block absolute top-0 bottom-0 right-0 md:w-1/2" aria-hidden="true">
|
||||
<img className="object-cover object-center w-full h-full" src={AuthImage} width="760" height="1024" alt="Authentication" />
|
||||
<img className="absolute top-1/4 left-0 transform -translate-x-1/2 ml-8 hidden lg:block" src={AuthDecoration} width="218" height="224" alt="Authentication decoration" />
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</main>
|
||||
);
|
||||
}
|
||||
|
||||
export default Signup;
|
||||
@@ -1,151 +0,0 @@
|
||||
import React, { useState } from 'react';
|
||||
|
||||
import Sidebar from '../../partials/Sidebar';
|
||||
import Header from '../../partials/Header';
|
||||
import AccordionBasic from '../../components/AccordionBasic';
|
||||
import AccordionTableItem from '../../components/AccordionTableItem';
|
||||
import AccordionTableRichItem from '../../components/AccordionTableRichItem';
|
||||
|
||||
import Image01 from '../../images/user-40-07.jpg';
|
||||
|
||||
function AccordionPage() {
|
||||
|
||||
const [sidebarOpen, setSidebarOpen] = useState(false);
|
||||
|
||||
const items = [
|
||||
{
|
||||
id: '0',
|
||||
image: Image01,
|
||||
customer: 'Mark Cameron',
|
||||
total: '$129.00',
|
||||
status: 'Refunded',
|
||||
items: '1',
|
||||
location: '🇲🇽 New Mexico, MX',
|
||||
type: 'Subscription',
|
||||
description: 'Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.'
|
||||
},
|
||||
];
|
||||
|
||||
const items2 = [
|
||||
{
|
||||
id: '0',
|
||||
image: Image01,
|
||||
customer: 'Mark Cameron',
|
||||
email: 'mark.cameron@app.com',
|
||||
location: '🇬🇧 London, UK',
|
||||
date: '22/01/2021',
|
||||
amount: '+249.88',
|
||||
descriptionTitle: 'Excepteur sint occaecat cupidatat.',
|
||||
descriptionBody: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam quis. Ut enim ad minim veniam quis. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.',
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<div className="flex h-screen overflow-hidden">
|
||||
|
||||
{/* Sidebar */}
|
||||
<Sidebar sidebarOpen={sidebarOpen} setSidebarOpen={setSidebarOpen} />
|
||||
|
||||
{/* Content area */}
|
||||
<div className="relative flex flex-col flex-1 overflow-y-auto overflow-x-hidden bg-white">
|
||||
|
||||
{/* Site header */}
|
||||
<Header sidebarOpen={sidebarOpen} setSidebarOpen={setSidebarOpen} />
|
||||
|
||||
<main>
|
||||
<div className="px-4 sm:px-6 lg:px-8 py-8 w-full max-w-9xl mx-auto">
|
||||
|
||||
{/* Page header */}
|
||||
<div className="mb-8">
|
||||
<h1 className="text-2xl md:text-3xl text-slate-800 font-bold">Accordion ✨</h1>
|
||||
</div>
|
||||
|
||||
<div className="border-t border-slate-200">
|
||||
|
||||
{/* Components */}
|
||||
<div className="space-y-8 mt-8">
|
||||
|
||||
{/* Basic Accordion */}
|
||||
<div>
|
||||
<h2 className="text-2xl text-slate-800 font-bold mb-6">Basic Accordion</h2>
|
||||
<AccordionBasic title="Accordion Title">
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam quis. Ut enim ad minim veniam quis. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
|
||||
</AccordionBasic>
|
||||
</div>
|
||||
|
||||
{/* Table Row with Accordion */}
|
||||
<div>
|
||||
<h2 className="text-2xl text-slate-800 font-bold mb-6">Table Row with Accordion</h2>
|
||||
{/* Start */}
|
||||
<div className="rounded-sm border border-slate-200">
|
||||
<div className="overflow-x-auto">
|
||||
<table className="table-auto w-full divide-y divide-slate-200">
|
||||
{
|
||||
items.map(item => {
|
||||
return (
|
||||
<AccordionTableItem
|
||||
key={item.id}
|
||||
id={item.id}
|
||||
image={item.image}
|
||||
customer={item.customer}
|
||||
total={item.total}
|
||||
status={item.status}
|
||||
items={item.items}
|
||||
location={item.location}
|
||||
type={item.type}
|
||||
description={item.description}
|
||||
/>
|
||||
)
|
||||
})
|
||||
}
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
{/* End */}
|
||||
</div>
|
||||
|
||||
{/* Rich Table Row with Accordion */}
|
||||
<div>
|
||||
<h2 className="text-2xl text-slate-800 font-bold mb-6">Rich Table Row with Accordion</h2>
|
||||
{/* Start */}
|
||||
<div className="rounded-sm border border-slate-200">
|
||||
<div className="overflow-x-auto">
|
||||
<table className="table-auto w-full divide-y divide-slate-200">
|
||||
{
|
||||
items2.map(item => {
|
||||
return (
|
||||
<AccordionTableRichItem
|
||||
key={item.id}
|
||||
id={item.id}
|
||||
image={item.image}
|
||||
customer={item.customer}
|
||||
email={item.email}
|
||||
location={item.location}
|
||||
date={item.date}
|
||||
amount={item.amount}
|
||||
descriptionTitle={item.descriptionTitle}
|
||||
descriptionBody={item.descriptionBody}
|
||||
/>
|
||||
)
|
||||
})
|
||||
}
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
{/* End */}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</main>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default AccordionPage;
|
||||
@@ -1,186 +0,0 @@
|
||||
import React, { useState } from 'react';
|
||||
|
||||
import Sidebar from '../../partials/Sidebar';
|
||||
import Header from '../../partials/Header';
|
||||
|
||||
function BadgePage() {
|
||||
|
||||
const [sidebarOpen, setSidebarOpen] = useState(false);
|
||||
|
||||
return (
|
||||
<div className="flex h-screen overflow-hidden">
|
||||
|
||||
{/* Sidebar */}
|
||||
<Sidebar sidebarOpen={sidebarOpen} setSidebarOpen={setSidebarOpen} />
|
||||
|
||||
{/* Content area */}
|
||||
<div className="relative flex flex-col flex-1 overflow-y-auto overflow-x-hidden bg-white">
|
||||
|
||||
{/* Site header */}
|
||||
<Header sidebarOpen={sidebarOpen} setSidebarOpen={setSidebarOpen} />
|
||||
|
||||
<main>
|
||||
<div className="px-4 sm:px-6 lg:px-8 py-8 w-full max-w-9xl mx-auto">
|
||||
|
||||
{/* Page header */}
|
||||
<div className="mb-8">
|
||||
<h1 className="text-2xl md:text-3xl text-slate-800 font-bold">Badge ✨</h1>
|
||||
</div>
|
||||
|
||||
<div className="border-t border-slate-200">
|
||||
|
||||
{/* Components */}
|
||||
<div className="space-y-8 mt-8">
|
||||
|
||||
{/* Basic Small */}
|
||||
<div>
|
||||
<h2 className="text-2xl text-slate-800 font-bold mb-6">Basic Small</h2>
|
||||
<div className="flex flex-wrap items-center -m-1.5">
|
||||
<div className="m-1.5">
|
||||
{/* Start */}
|
||||
<div className="text-xs inline-flex font-medium bg-indigo-100 text-indigo-600 rounded-full text-center px-2.5 py-1">Working on</div>
|
||||
{/* End */}
|
||||
</div>
|
||||
<div className="m-1.5">
|
||||
{/* Start */}
|
||||
<div className="text-xs inline-flex font-medium bg-sky-100 text-sky-600 rounded-full text-center px-2.5 py-1">Exciting news</div>
|
||||
{/* End */}
|
||||
</div>
|
||||
<div className="m-1.5">
|
||||
{/* Start */}
|
||||
<div className="text-xs inline-flex font-medium bg-emerald-100 text-emerald-600 rounded-full text-center px-2.5 py-1">Product</div>
|
||||
{/* End */}
|
||||
</div>
|
||||
<div className="m-1.5">
|
||||
{/* Start */}
|
||||
<div className="text-xs inline-flex font-medium bg-amber-100 text-amber-600 rounded-full text-center px-2.5 py-1">Announcement</div>
|
||||
{/* End */}
|
||||
</div>
|
||||
<div className="m-1.5">
|
||||
{/* Start */}
|
||||
<div className="text-xs inline-flex font-medium bg-rose-100 text-rose-600 rounded-full text-center px-2.5 py-1">Bug Fix</div>
|
||||
{/* End */}
|
||||
</div>
|
||||
<div className="m-1.5">
|
||||
{/* Start */}
|
||||
<div className="text-xs inline-flex font-medium bg-blue-100 text-blue-600 rounded-full text-center px-2.5 py-1">Customer Stories</div>
|
||||
{/* End */}
|
||||
</div>
|
||||
<div className="m-1.5">
|
||||
{/* Start */}
|
||||
<div className="text-xs inline-flex font-medium bg-slate-100 text-slate-500 rounded-full text-center px-2.5 py-1">All Stories</div>
|
||||
{/* End */}
|
||||
</div>
|
||||
<div className="m-1.5">
|
||||
{/* Start */}
|
||||
<div className="text-xs inline-flex font-medium bg-slate-700 text-slate-100 rounded-full text-center px-2.5 py-1">All Stories</div>
|
||||
{/* End */}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Basic Large */}
|
||||
<div>
|
||||
<h2 className="text-2xl text-slate-800 font-bold mb-6">Basic Large</h2>
|
||||
<div className="flex flex-wrap items-center -m-1.5">
|
||||
<div className="m-1.5">
|
||||
{/* Start */}
|
||||
<div className="text-sm inline-flex font-medium bg-indigo-100 text-indigo-600 rounded-full text-center px-2.5 py-1">Working on</div>
|
||||
{/* End */}
|
||||
</div>
|
||||
<div className="m-1.5">
|
||||
{/* Start */}
|
||||
<div className="text-sm inline-flex font-medium bg-sky-100 text-sky-600 rounded-full text-center px-2.5 py-1">Exciting news</div>
|
||||
{/* End */}
|
||||
</div>
|
||||
<div className="m-1.5">
|
||||
{/* Start */}
|
||||
<div className="text-sm inline-flex font-medium bg-emerald-100 text-emerald-600 rounded-full text-center px-2.5 py-1">Product</div>
|
||||
{/* End */}
|
||||
</div>
|
||||
<div className="m-1.5">
|
||||
{/* Start */}
|
||||
<div className="text-sm inline-flex font-medium bg-amber-100 text-amber-600 rounded-full text-center px-2.5 py-1">Announcement</div>
|
||||
{/* End */}
|
||||
</div>
|
||||
<div className="m-1.5">
|
||||
{/* Start */}
|
||||
<div className="text-sm inline-flex font-medium bg-rose-100 text-rose-600 rounded-full text-center px-2.5 py-1">Bug Fix</div>
|
||||
{/* End */}
|
||||
</div>
|
||||
<div className="m-1.5">
|
||||
{/* Start */}
|
||||
<div className="text-sm inline-flex font-medium bg-blue-100 text-blue-600 rounded-full text-center px-2.5 py-1">Customer Stories</div>
|
||||
{/* End */}
|
||||
</div>
|
||||
<div className="m-1.5">
|
||||
{/* Start */}
|
||||
<div className="text-sm inline-flex font-medium bg-slate-100 text-slate-500 rounded-full text-center px-2.5 py-1">All Stories</div>
|
||||
{/* End */}
|
||||
</div>
|
||||
<div className="m-1.5">
|
||||
{/* Start */}
|
||||
<div className="text-sm inline-flex font-medium bg-slate-700 text-slate-100 rounded-full text-center px-2.5 py-1">All Stories</div>
|
||||
{/* End */}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Basic with Icon */}
|
||||
<div>
|
||||
<h2 className="text-2xl text-slate-800 font-bold mb-6">Basic with Icon</h2>
|
||||
<div className="flex flex-wrap items-center -m-1.5">
|
||||
<div className="m-1.5">
|
||||
{/* Start */}
|
||||
<div className="inline-flex items-center text-xs font-medium text-slate-100 bg-slate-700 rounded-full text-center px-2 py-0.5">
|
||||
<svg className="w-3 h-3 shrink-0 fill-current text-amber-500 mr-1" viewBox="0 0 12 12">
|
||||
<path d="M11.953 4.29a.5.5 0 00-.454-.292H6.14L6.984.62A.5.5 0 006.12.173l-6 7a.5.5 0 00.379.825h5.359l-.844 3.38a.5.5 0 00.864.445l6-7a.5.5 0 00.075-.534z" />
|
||||
</svg>
|
||||
<span>Special Offer</span>
|
||||
</div>
|
||||
{/* End */}
|
||||
</div>
|
||||
<div className="m-1.5">
|
||||
{/* Start */}
|
||||
<div className="inline-flex items-center text-sm font-medium text-slate-100 bg-slate-700 rounded-full text-center px-2 py-0.5">
|
||||
<svg className="w-3 h-3 shrink-0 fill-current text-amber-500 mr-1" viewBox="0 0 12 12">
|
||||
<path d="M11.953 4.29a.5.5 0 00-.454-.292H6.14L6.984.62A.5.5 0 006.12.173l-6 7a.5.5 0 00.379.825h5.359l-.844 3.38a.5.5 0 00.864.445l6-7a.5.5 0 00.075-.534z" />
|
||||
</svg>
|
||||
<span>Special Offer</span>
|
||||
</div>
|
||||
{/* End */}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Basic for Charts */}
|
||||
<div>
|
||||
<h2 className="text-2xl text-slate-800 font-bold mb-6">Basic for Charts</h2>
|
||||
<div className="flex flex-wrap items-center -m-1.5">
|
||||
<div className="m-1.5">
|
||||
{/* Start */}
|
||||
<div className="text-sm font-semibold text-white px-1.5 bg-emerald-500 rounded-full">+29%</div>
|
||||
{/* End */}
|
||||
</div>
|
||||
<div className="m-1.5">
|
||||
{/* Start */}
|
||||
<div className="text-sm font-semibold text-white px-1.5 bg-amber-500 rounded-full">-14%</div>
|
||||
{/* End */}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</main>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default BadgePage;
|
||||
@@ -1,235 +0,0 @@
|
||||
import React, { useState } from 'react';
|
||||
|
||||
import Sidebar from '../../partials/Sidebar';
|
||||
import Header from '../../partials/Header';
|
||||
|
||||
function ButtonPage() {
|
||||
|
||||
const [sidebarOpen, setSidebarOpen] = useState(false);
|
||||
|
||||
return (
|
||||
<div className="flex h-screen overflow-hidden">
|
||||
|
||||
{/* Sidebar */}
|
||||
<Sidebar sidebarOpen={sidebarOpen} setSidebarOpen={setSidebarOpen} />
|
||||
|
||||
{/* Content area */}
|
||||
<div className="relative flex flex-col flex-1 overflow-y-auto overflow-x-hidden bg-white">
|
||||
|
||||
{/* Site header */}
|
||||
<Header sidebarOpen={sidebarOpen} setSidebarOpen={setSidebarOpen} />
|
||||
|
||||
<main>
|
||||
<div className="px-4 sm:px-6 lg:px-8 py-8 w-full max-w-9xl mx-auto">
|
||||
|
||||
{/* Page header */}
|
||||
<div className="mb-8">
|
||||
<h1 className="text-2xl md:text-3xl text-slate-800 font-bold">Button ✨</h1>
|
||||
</div>
|
||||
|
||||
<div className="border-t border-slate-200">
|
||||
|
||||
{/* Components */}
|
||||
<div className="space-y-8 mt-8">
|
||||
|
||||
{/* Appearances */}
|
||||
<div>
|
||||
<h2 className="text-2xl text-slate-800 font-bold mb-6">Appearances</h2>
|
||||
<div className="flex flex-wrap items-center -m-1.5">
|
||||
<div className="m-1.5">
|
||||
{/* Start */}
|
||||
<button className="btn bg-indigo-500 hover:bg-indigo-600 text-white">Primary</button>
|
||||
{/* End */}
|
||||
</div>
|
||||
<div className="m-1.5">
|
||||
{/* Start */}
|
||||
<button className="btn border-slate-200 hover:border-slate-300 text-indigo-500">Secondary</button>
|
||||
{/* End */}
|
||||
</div>
|
||||
<div className="m-1.5">
|
||||
{/* Start */}
|
||||
<button className="btn border-slate-200 hover:border-slate-300 text-slate-600">Tertiary</button>
|
||||
{/* End */}
|
||||
</div>
|
||||
<div className="m-1.5">
|
||||
{/* Start */}
|
||||
<button className="btn bg-rose-500 hover:bg-rose-600 text-white">Danger</button>
|
||||
{/* End */}
|
||||
</div>
|
||||
<div className="m-1.5">
|
||||
{/* Start */}
|
||||
<button className="btn border-slate-200 hover:border-slate-300 text-rose-500">Danger</button>
|
||||
{/* End */}
|
||||
</div>
|
||||
<div className="m-1.5">
|
||||
{/* Start */}
|
||||
<button className="btn bg-emerald-500 hover:bg-emerald-600 text-white">Success</button>
|
||||
{/* End */}
|
||||
</div>
|
||||
<div className="m-1.5">
|
||||
{/* Start */}
|
||||
<button className="btn border-slate-200 hover:border-slate-300 text-emerald-500">Success</button>
|
||||
{/* End */}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* States */}
|
||||
<div>
|
||||
<h2 className="text-2xl text-slate-800 font-bold mb-6">States</h2>
|
||||
<div className="flex flex-wrap items-center -m-1.5">
|
||||
<div className="m-1.5">
|
||||
{/* Start */}
|
||||
<button className="btn bg-indigo-500 hover:bg-indigo-600 text-white disabled:border-slate-200 disabled:bg-slate-100 disabled:text-slate-400 disabled:cursor-not-allowed shadow-none" disabled>Disabled</button>
|
||||
{/* End */}
|
||||
</div>
|
||||
<div className="m-1.5">
|
||||
{/* Start */}
|
||||
<button className="btn bg-indigo-500 hover:bg-indigo-600 text-white disabled:border-slate-200 disabled:bg-slate-100 disabled:text-slate-400 disabled:cursor-not-allowed shadow-none" disabled>
|
||||
<svg className="animate-spin w-4 h-4 fill-current shrink-0" viewBox="0 0 16 16">
|
||||
<path d="M8 16a7.928 7.928 0 01-3.428-.77l.857-1.807A6.006 6.006 0 0014 8c0-3.309-2.691-6-6-6a6.006 6.006 0 00-5.422 8.572l-1.806.859A7.929 7.929 0 010 8c0-4.411 3.589-8 8-8s8 3.589 8 8-3.589 8-8 8z" />
|
||||
</svg>
|
||||
<span className="ml-2">Loading</span>
|
||||
</button>
|
||||
{/* End */}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Sizes */}
|
||||
<div>
|
||||
<h2 className="text-2xl text-slate-800 font-bold mb-6">Sizes</h2>
|
||||
<div className="flex flex-wrap items-center -m-1.5">
|
||||
<div className="m-1.5">
|
||||
{/* Start */}
|
||||
<button className="btn-xs bg-indigo-500 hover:bg-indigo-600 text-white">Button</button>
|
||||
{/* End */}
|
||||
</div>
|
||||
<div className="m-1.5">
|
||||
{/* Start */}
|
||||
<button className="btn-sm bg-indigo-500 hover:bg-indigo-600 text-white">Button</button>
|
||||
{/* End */}
|
||||
</div>
|
||||
<div className="m-1.5">
|
||||
{/* Start */}
|
||||
<button className="btn bg-indigo-500 hover:bg-indigo-600 text-white">Button</button>
|
||||
{/* End */}
|
||||
</div>
|
||||
<div className="m-1.5">
|
||||
{/* Start */}
|
||||
<button className="btn-lg bg-indigo-500 hover:bg-indigo-600 text-white">Button</button>
|
||||
{/* End */}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Buttons with an Icon */}
|
||||
<div>
|
||||
<h2 className="text-2xl text-slate-800 font-bold mb-6">Buttons with an Icon</h2>
|
||||
<div className="flex flex-wrap items-center -m-1.5">
|
||||
<div className="m-1.5">
|
||||
{/* Start */}
|
||||
<button className="btn bg-indigo-500 hover:bg-indigo-600 text-white">
|
||||
<svg className="w-4 h-4 fill-current opacity-50 shrink-0" viewBox="0 0 16 16">
|
||||
<path d="M15 7H9V1c0-.6-.4-1-1-1S7 .4 7 1v6H1c-.6 0-1 .4-1 1s.4 1 1 1h6v6c0 .6.4 1 1 1s1-.4 1-1V9h6c.6 0 1-.4 1-1s-.4-1-1-1z" />
|
||||
</svg>
|
||||
<span className="ml-2">Add Event</span>
|
||||
</button>
|
||||
{/* End */}
|
||||
</div>
|
||||
<div className="m-1.5">
|
||||
{/* Start */}
|
||||
<button className="btn border-slate-200 hover:border-slate-300 text-slate-600">
|
||||
<svg className="w-4 h-4 fill-current text-slate-500 shrink-0" 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" />
|
||||
</svg>
|
||||
<span className="ml-2">Edit Content</span>
|
||||
</button>
|
||||
{/* End */}
|
||||
</div>
|
||||
<div className="m-1.5">
|
||||
{/* Start */}
|
||||
<button className="btn border-slate-200 hover:border-slate-300 text-rose-500">
|
||||
<svg className="w-4 h-4 fill-current shrink-0" viewBox="0 0 16 16">
|
||||
<path d="M5 7h2v6H5V7zm4 0h2v6H9V7zm3-6v2h4v2h-1v10c0 .6-.4 1-1 1H2c-.6 0-1-.4-1-1V5H0V3h4V1c0-.6.4-1 1-1h6c.6 0 1 .4 1 1zM6 2v1h4V2H6zm7 3H3v9h10V5z" />
|
||||
</svg>
|
||||
<span className="ml-2">Delete</span>
|
||||
</button>
|
||||
{/* End */}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Icon Buttons */}
|
||||
<div>
|
||||
<h2 className="text-2xl text-slate-800 font-bold mb-6">Icon Buttons</h2>
|
||||
<div className="flex flex-wrap items-center -m-1.5">
|
||||
<div className="m-1.5">
|
||||
{/* Start */}
|
||||
<button className="btn border-slate-200 hover:border-slate-300">
|
||||
<svg className="w-4 h-4 fill-current text-slate-500 shrink-0" 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" />
|
||||
</svg>
|
||||
</button>
|
||||
{/* End */}
|
||||
</div>
|
||||
<div className="m-1.5">
|
||||
{/* Start */}
|
||||
<button className="btn border-slate-200 hover:border-slate-300">
|
||||
<svg className="w-4 h-4 fill-current text-rose-500 shrink-0" viewBox="0 0 16 16">
|
||||
<path d="M5 7h2v6H5V7zm4 0h2v6H9V7zm3-6v2h4v2h-1v10c0 .6-.4 1-1 1H2c-.6 0-1-.4-1-1V5H0V3h4V1c0-.6.4-1 1-1h6c.6 0 1 .4 1 1zM6 2v1h4V2H6zm7 3H3v9h10V5z" />
|
||||
</svg>
|
||||
</button>
|
||||
{/* End */}
|
||||
</div>
|
||||
<div className="m-1.5">
|
||||
{/* Start */}
|
||||
<button className="btn border-slate-200 hover:border-slate-300">
|
||||
<svg className="w-4 h-4 fill-current text-indigo-500 shrink-0" viewBox="0 0 16 16">
|
||||
<path d="M14.3 2.3L5 11.6 1.7 8.3c-.4-.4-1-.4-1.4 0-.4.4-.4 1 0 1.4l4 4c.2.2.4.3.7.3.3 0 .5-.1.7-.3l10-10c.4-.4.4-1 0-1.4-.4-.4-1-.4-1.4 0z" />
|
||||
</svg>
|
||||
</button>
|
||||
{/* End */}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Button Groups */}
|
||||
<div>
|
||||
<h2 className="text-2xl text-slate-800 font-bold mb-6">Button Groups</h2>
|
||||
<div className="flex flex-wrap items-center -m-1.5">
|
||||
<div className="m-1.5">
|
||||
{/* Start */}
|
||||
<div className="flex flex-wrap -space-x-px">
|
||||
<button className="btn bg-indigo-600 text-white rounded-none border-l-indigo-400 first:rounded-l last:rounded-r first:border-r-transparent">Weekly</button>
|
||||
<button className="btn bg-indigo-500 hover:bg-indigo-600 text-indigo-100 rounded-none border-l-indigo-400 first:rounded-l last:rounded-r first:border-r-transparent">Monthly</button>
|
||||
<button className="btn bg-indigo-500 hover:bg-indigo-600 text-indigo-100 rounded-none border-l-indigo-400 first:rounded-l last:rounded-r first:border-r-transparent">Yearly</button>
|
||||
</div>
|
||||
{/* End */}
|
||||
</div>
|
||||
<div className="m-1.5">
|
||||
{/* Start */}
|
||||
<div className="flex flex-wrap -space-x-px">
|
||||
<button className="btn bg-slate-50 border-slate-200 hover:bg-slate-50 text-indigo-500 rounded-none first:rounded-l last:rounded-r">Weekly</button>
|
||||
<button className="btn bg-white border-slate-200 hover:bg-slate-50 text-slate-600 rounded-none first:rounded-l last:rounded-r">Monthly</button>
|
||||
<button className="btn bg-white border-slate-200 hover:bg-slate-50 text-slate-600 rounded-none first:rounded-l last:rounded-r">Yearly</button>
|
||||
</div>
|
||||
{/* End */}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</main>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default ButtonPage;
|
||||
@@ -1,34 +1,129 @@
|
||||
import React, { useState } from 'react';
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { store } 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 ProfileTable from '../../partials/profile/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';
|
||||
import { labelMap } from '../../shared/labelMap';
|
||||
import { statusMap } from '../../shared/statusMap';
|
||||
|
||||
const initialPropertyValues = [
|
||||
'First name',
|
||||
'Second name',
|
||||
'Birthdate',
|
||||
'Gender',
|
||||
'National doctype',
|
||||
'National doc ID',
|
||||
'National doc issue date',
|
||||
'National doc expiry date',
|
||||
];
|
||||
|
||||
const Profile = observer(() => {
|
||||
const defaultValues = {
|
||||
label: '',
|
||||
value: '',
|
||||
seed: String(Math.floor(Math.random() * 90000000000000000000), 10),
|
||||
};
|
||||
|
||||
function Profile () {
|
||||
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 [storeOnBlockchain, setStoreOnBlockchain] = useState(false);
|
||||
const [addPanelOpen, setAddPanelOpen] = useState(false);
|
||||
const [sharePanelOpen, setSharePanelOpen] = useState(false);
|
||||
const [updatePanelOpen, setUpdatePanelOpen] = useState(false);
|
||||
const [selectedItems, setSelectedItems] = useState([]);
|
||||
const [propertyValues, setPropertyValues] = useState([]);
|
||||
const [updatedValues, setUpdatedValues] = useState([defaultValues]);
|
||||
const [addedValues, setAddedValues] = useState(defaultValues);
|
||||
const [isCheck, setIsCheck] = useState([]);
|
||||
const [alreadyExists, setAlreadyExists] = useState(false);
|
||||
const [blockChainValue, setBlockChainValue] = useState('');
|
||||
const [publicKey, setPublicKey] = useState('');
|
||||
|
||||
useEffect(() => {
|
||||
handleSelectedItems(isCheck);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [isCheck]);
|
||||
|
||||
const handleClick = (e) => {
|
||||
const { id, checked } = e.target;
|
||||
setIsCheck([...isCheck, id]);
|
||||
if (!checked || !id) {
|
||||
setIsCheck(isCheck.filter((item) => item !== id));
|
||||
}
|
||||
};
|
||||
|
||||
const openHint = () => {
|
||||
if (!addedValues.label) {
|
||||
setPropertyValues(initialPropertyValues);
|
||||
}
|
||||
};
|
||||
|
||||
const changeAddedValues = (value, field) => {
|
||||
setAddedValues((prevState) => ({
|
||||
...prevState,
|
||||
[field]: value,
|
||||
}));
|
||||
};
|
||||
|
||||
const changeUpdatedValues = (value, field, key) => {
|
||||
if (field === 'value') {
|
||||
setBlockChainValue(value);
|
||||
}
|
||||
setUpdatedValues((prevState) =>
|
||||
prevState.map((elem) =>
|
||||
elem.key === key
|
||||
? {
|
||||
...elem,
|
||||
[field]: value,
|
||||
}
|
||||
: elem
|
||||
)
|
||||
);
|
||||
};
|
||||
|
||||
const selectHint = (element) => {
|
||||
changeAddedValues(element, 'label');
|
||||
setPropertyValues([]);
|
||||
};
|
||||
|
||||
const closeHint = (eventTarget) => {
|
||||
if (!eventTarget || eventTarget.tabIndex !== -1) {
|
||||
setPropertyValues([]);
|
||||
}
|
||||
};
|
||||
|
||||
const handleSelectedItems = (selectedItems) => {
|
||||
setSelectedItems([...selectedItems]);
|
||||
setUpdatedValues(
|
||||
store.decryptedAccountData
|
||||
.filter(({ key }) => selectedItems.includes(key))
|
||||
.map((elem) =>
|
||||
!elem.seed
|
||||
? {
|
||||
...elem,
|
||||
seed: String(
|
||||
Math.floor(Math.random() * 90000000000000000000),
|
||||
10
|
||||
),
|
||||
}
|
||||
: 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);
|
||||
}
|
||||
@@ -37,157 +132,154 @@ function Profile () {
|
||||
const openAddPanel = () => {
|
||||
setAddPanelOpen(true);
|
||||
setButtonPanelOpen(false);
|
||||
}
|
||||
};
|
||||
|
||||
const sendAddedData = () => {
|
||||
const checkingAddedData = !store.decryptedAccountData.some(
|
||||
(element) => element.label === addedValues.label
|
||||
);
|
||||
setAlreadyExists(!checkingAddedData);
|
||||
if (checkingAddedData) {
|
||||
setAddPanelOpen(false);
|
||||
setButtonPanelOpen(true);
|
||||
setAddedValues(defaultValues);
|
||||
addDataParameters();
|
||||
}
|
||||
};
|
||||
|
||||
const sendUpdatedData = () => {
|
||||
setUpdatePanelOpen(false);
|
||||
changeDataParameters();
|
||||
setChangePanelOpen(true);
|
||||
setIsCheck([]);
|
||||
};
|
||||
|
||||
const deleteDataParameters = () => {
|
||||
const changeData = store.decryptedAccountData.filter(
|
||||
(item) => !selectedItems.includes(item.key)
|
||||
);
|
||||
store.pushAccountData(changeData);
|
||||
if (storeOnBlockchain)
|
||||
store.pushAccountDataToBlockchain(
|
||||
changeData.filter((elem) => elem.status !== 'Stored')
|
||||
);
|
||||
};
|
||||
|
||||
const changeInitialArray = () => {
|
||||
let newArr = [];
|
||||
store.decryptedAccountData.map((elem) => {
|
||||
updatedValues.forEach((item) => {
|
||||
if (elem.label === item.label) {
|
||||
newArr.push({
|
||||
...elem,
|
||||
status: 'new',
|
||||
value: item.value,
|
||||
seed: item.seed,
|
||||
});
|
||||
}
|
||||
});
|
||||
if (!newArr.find((element) => element.label === elem.label)) {
|
||||
newArr.push(elem);
|
||||
}
|
||||
});
|
||||
return newArr;
|
||||
};
|
||||
|
||||
const changeDataParameters = () => {
|
||||
const updatedData = changeInitialArray();
|
||||
store.pushAccountData(updatedData);
|
||||
if (storeOnBlockchain)
|
||||
store.pushAccountDataToBlockchain(
|
||||
updatedData.filter((elem) => elem.status !== 'Stored')
|
||||
);
|
||||
};
|
||||
|
||||
const shareAccountData = () => {
|
||||
const sharedData = store.decryptedAccountData.filter((item) =>
|
||||
selectedItems.includes(item.key)
|
||||
);
|
||||
store.pushSharedData(sharedData, publicKey);
|
||||
cancelSharePanel();
|
||||
};
|
||||
|
||||
const addDataParameters = () => {
|
||||
const label = addedValues.label.toLowerCase().split(' ').join('');
|
||||
if (labelMap[label])
|
||||
addedValues.key = addedValues.label.toLowerCase().split(' ').join('');
|
||||
else addedValues.key = addedValues.label;
|
||||
store.pushAccountData(store.decryptedAccountData.concat(addedValues));
|
||||
if (storeOnBlockchain)
|
||||
store.pushAccountDataToBlockchain(
|
||||
store.decryptedAccountData
|
||||
.concat(addedValues)
|
||||
.filter((elem) => elem.status !== 'Stored')
|
||||
);
|
||||
};
|
||||
|
||||
const cancelAddPanel = () => {
|
||||
setAddedValues(defaultValues);
|
||||
setAddPanelOpen(false);
|
||||
setButtonPanelOpen(true);
|
||||
}
|
||||
};
|
||||
|
||||
const cancelUpdatePanel = () => {
|
||||
setUpdatedValues(
|
||||
store.decryptedAccountData
|
||||
.filter(({ key }) => selectedItems.includes(key))
|
||||
.map((elem) =>
|
||||
!elem.seed
|
||||
? {
|
||||
...elem,
|
||||
seed: String(
|
||||
Math.floor(Math.random() * 90000000000000000000),
|
||||
10
|
||||
),
|
||||
}
|
||||
: elem
|
||||
)
|
||||
);
|
||||
setUpdatePanelOpen(false);
|
||||
setChangePanelOpen(true);
|
||||
setIsCheck([]);
|
||||
};
|
||||
|
||||
const openRemovePanel = () => {
|
||||
setRemovePanelOpen(true);
|
||||
setChangePanelOpen(false);
|
||||
}
|
||||
};
|
||||
|
||||
const applyRemovePanel = () => {
|
||||
const openSharePanel = () => {
|
||||
setSharePanelOpen(true);
|
||||
setChangePanelOpen(false);
|
||||
};
|
||||
|
||||
const cancelSharePanel = () => {
|
||||
setSharePanelOpen(false);
|
||||
setChangePanelOpen(true);
|
||||
};
|
||||
|
||||
const openUpdatePanel = () => {
|
||||
setUpdatePanelOpen(true);
|
||||
setChangePanelOpen(false);
|
||||
};
|
||||
|
||||
const applyDataDeletion = () => {
|
||||
setRemovePanelOpen(false);
|
||||
setButtonPanelOpen(true);
|
||||
}
|
||||
deleteDataParameters();
|
||||
setIsCheck([]);
|
||||
};
|
||||
|
||||
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 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,18 +314,27 @@ function Profile () {
|
||||
</ul>
|
||||
</div>
|
||||
{/* Table */}
|
||||
<ProfileTable selectedItems={handleSelectedItems} userData={userData}/>
|
||||
<div>
|
||||
<ProfileTable
|
||||
isCheck={isCheck}
|
||||
handleClick={handleClick}
|
||||
userData={store.decryptedAccountData}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
{/* Left sidebar */}
|
||||
<div>
|
||||
{/* Button panel*/}
|
||||
<div className={`${!buttonPanelOpen && "hidden"} ml-2.5`}>
|
||||
<div className={`${!buttonPanelOpen && 'hidden'} ml-2.5`}>
|
||||
<div className="bg-white px-5 py-[43px] shadow-lg rounded-sm border border-slate-200 lg:w-72 xl:w-80">
|
||||
<button
|
||||
className="btn w-full bg-indigo-500 hover:bg-indigo-600 text-white"
|
||||
onClick={openAddPanel}
|
||||
>
|
||||
<svg className="w-4 h-4 fill-current shrink-0" viewBox="0 0 16 16">
|
||||
<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" />
|
||||
</svg>
|
||||
<span className="ml-1">Add new field</span>
|
||||
@@ -242,28 +343,241 @@ function Profile () {
|
||||
</div>
|
||||
<div className="ml-2.5">
|
||||
{/* Add panel */}
|
||||
<div className={`${!addPanelOpen && 'hidden'} bg-white p-5 shadow-lg rounded-sm border border-slate-200 lg:w-72 xl:w-80 mb-11`}>
|
||||
<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 />
|
||||
</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 />
|
||||
</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 />
|
||||
<div
|
||||
className={`${
|
||||
!addPanelOpen && 'hidden'
|
||||
} relative flex flex-col bg-white p-5 shadow-lg rounded-sm border border-slate-200 lg:w-72 xl:w-80 mb-11`}
|
||||
>
|
||||
<div className="relative z-20">
|
||||
<label
|
||||
className="block text-sm font-medium mb-1"
|
||||
htmlFor="mandatory"
|
||||
>
|
||||
Property <span className="text-rose-500">*</span>
|
||||
</label>
|
||||
<input
|
||||
autoComplete="off"
|
||||
id="label"
|
||||
className={`form-input w-full ${
|
||||
alreadyExists && 'border-rose-300'
|
||||
}`}
|
||||
type="text"
|
||||
required
|
||||
onInput={(e) => handleInput(e.target.value, 'label')}
|
||||
value={addedValues.label}
|
||||
onClick={openHint}
|
||||
onBlur={(e) => closeHint(e.relatedTarget)}
|
||||
/>
|
||||
<div
|
||||
tabIndex="-1"
|
||||
className={`absolute w-full box-border bg-white 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
|
||||
className="hover:text-indigo-600 cursor-pointer"
|
||||
key={index}
|
||||
onClick={() => selectHint(element)}
|
||||
>
|
||||
{element}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
{alreadyExists && (
|
||||
<div className="text-xs mt-1 text-rose-500">
|
||||
This property already added!
|
||||
</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="my-3 z-10">
|
||||
<label
|
||||
className="block text-sm font-medium mb-1"
|
||||
htmlFor="mandatory"
|
||||
>
|
||||
Value <span className="text-rose-500">*</span>
|
||||
</label>
|
||||
<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 className="z-10">
|
||||
<label
|
||||
className="block text-sm font-medium mb-1"
|
||||
htmlFor="mandatory"
|
||||
>
|
||||
Seed <span className="text-rose-500">*</span>
|
||||
</label>
|
||||
<input
|
||||
autoComplete="off"
|
||||
id="seed"
|
||||
className="form-input w-full"
|
||||
type="text"
|
||||
required
|
||||
onClick={() => setPropertyValues([])}
|
||||
onChange={(e) =>
|
||||
changeAddedValues(e.target.value, 'seed')
|
||||
}
|
||||
value={addedValues.seed}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex flex-row z-10 justify-between pt-[18px] 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)} />
|
||||
<label className="bg-slate-400" htmlFor="switch-1">
|
||||
<span className="bg-white shadow-sm" aria-hidden="true"></span>
|
||||
<input
|
||||
type="checkbox"
|
||||
id="blockcheined"
|
||||
className="sr-only"
|
||||
checked={storeOnBlockchain}
|
||||
onChange={() =>
|
||||
setStoreOnBlockchain(!storeOnBlockchain)
|
||||
}
|
||||
/>
|
||||
<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 z-10 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={cancelAddPanel}
|
||||
>
|
||||
Cancel
|
||||
</button>
|
||||
<button
|
||||
className="btn-sm bg-indigo-500 hover:bg-indigo-600 text-white"
|
||||
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
|
||||
/>
|
||||
</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.status === statusMap.blockchained
|
||||
? blockChainValue
|
||||
: 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="text"
|
||||
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={storeOnBlockchain}
|
||||
onChange={() =>
|
||||
setStoreOnBlockchain(!storeOnBlockchain)
|
||||
}
|
||||
/>
|
||||
<label className="bg-slate-400" htmlFor="switch-1">
|
||||
<span
|
||||
className="bg-white shadow-sm"
|
||||
aria-hidden="true"
|
||||
></span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
@@ -272,33 +586,59 @@ function Profile () {
|
||||
<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={cancelAddPanel}
|
||||
onClick={cancelUpdatePanel}
|
||||
>
|
||||
Cansel
|
||||
Cancel
|
||||
</button>
|
||||
<button
|
||||
className="btn-sm bg-indigo-500 hover:bg-indigo-600 text-white"
|
||||
onClick={cancelAddPanel}
|
||||
onClick={sendUpdatedData}
|
||||
>
|
||||
Send
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
{/* Remove panel */}
|
||||
<div className={`${!removePanelOpen && 'hidden'} bg-white p-5 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.5">Summary</h2>
|
||||
<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>
|
||||
))}
|
||||
{store.decryptedAccountData
|
||||
.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-[23px] items-center">
|
||||
<span className="block text-sm font-medium">On blockchain too</span>
|
||||
<div className="flex flex-row justify-between pt-[16px] pb-7 items-center">
|
||||
<span className="block text-sm font-medium">
|
||||
On blockchain too
|
||||
</span>
|
||||
<div className="flex items-center">
|
||||
<div className="form-switch">
|
||||
<input type="checkbox" id="switch-1" 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>
|
||||
<input
|
||||
type="checkbox"
|
||||
id="switch-1"
|
||||
className="sr-only"
|
||||
checked={storeOnBlockchain}
|
||||
onChange={() =>
|
||||
setStoreOnBlockchain(!storeOnBlockchain)
|
||||
}
|
||||
/>
|
||||
<label className="bg-slate-400" htmlFor="switch-1">
|
||||
<span
|
||||
className="bg-white shadow-sm"
|
||||
aria-hidden="true"
|
||||
></span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
@@ -306,37 +646,109 @@ 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"
|
||||
>
|
||||
<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" />
|
||||
</svg>
|
||||
<span className="ml-2">Apply</span>
|
||||
</button>
|
||||
</div>
|
||||
<div className="flex justify-center">
|
||||
<span className="text-descriptionSize text-slate-500 font-normal italic text-center">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do Terms.</span>
|
||||
<span className="text-descriptionSize text-slate-500 font-normal italic text-center">
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit,
|
||||
sed do Terms.
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
{/* Share panel */}
|
||||
<div
|
||||
className={`${
|
||||
!sharePanelOpen && 'hidden'
|
||||
} bg-white px-5 pt-4 shadow-lg rounded-sm border border-slate-200 mb-12 lg:w-72 xl:w-80`}
|
||||
>
|
||||
<div className="relative z-20">
|
||||
<div className="z-10">
|
||||
<label
|
||||
className="block text-sm font-medium mb-1"
|
||||
htmlFor="mandatory"
|
||||
>
|
||||
Public Key <span className="text-rose-500">*</span>
|
||||
</label>
|
||||
<input
|
||||
autoComplete="off"
|
||||
id="seed"
|
||||
className="form-input w-full"
|
||||
type="text"
|
||||
required
|
||||
onChange={(e) => setPublicKey(e.target.value)}
|
||||
value={publicKey}
|
||||
/>
|
||||
</div>
|
||||
{/* Buttons */}
|
||||
<div className="flex flex-row z-10 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={cancelSharePanel}
|
||||
>
|
||||
Cancel
|
||||
</button>
|
||||
<button
|
||||
className="btn-sm bg-indigo-500 hover:bg-indigo-600 text-white"
|
||||
onClick={shareAccountData}
|
||||
>
|
||||
Share
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/* Details */}
|
||||
<div className={`${(removePanelOpen || addPanelOpen) || 'hidden'} drop-shadow-lg`}>
|
||||
<div
|
||||
className={`${
|
||||
(!(removePanelOpen || addPanelOpen) ||
|
||||
!storeOnBlockchain) &&
|
||||
'hidden'
|
||||
} drop-shadow-lg`}
|
||||
>
|
||||
{/* Top */}
|
||||
<div className="bg-white rounded-t-xl px-5 pb-4 text-center">
|
||||
<div className="mb-3 text-center">
|
||||
<img className="inline-flex w-12 h-12 rounded-full -mt-6" src={Image} width="48" height="48" alt="Transaction 04" />
|
||||
<img
|
||||
className="inline-flex w-12 h-12 rounded-full -mt-6"
|
||||
src={Image}
|
||||
width="48"
|
||||
height="48"
|
||||
alt="Transaction 04"
|
||||
/>
|
||||
</div>
|
||||
<div className="mt-[31px] text-2xl font-semibold text-emerald-500 mb-1">
|
||||
0.012 IDN
|
||||
</div>
|
||||
<div className="text-sm font-medium text-slate-800 mb-3">
|
||||
Total amount fee
|
||||
</div>
|
||||
<div className="mt-[31px] text-2xl font-semibold text-emerald-500 mb-1">0.012 IDN</div>
|
||||
<div className="text-sm font-medium text-slate-800 mb-3">Total amount fee</div>
|
||||
</div>
|
||||
{/* Divider */}
|
||||
<div className="flex justify-between items-center" aria-hidden="true">
|
||||
<svg className="w-5 h-5 fill-white" xmlns="http://www.w3.org/2000/svg">
|
||||
<div
|
||||
className="flex justify-between items-center"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<svg
|
||||
className="w-5 h-5 fill-white"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path d="M0 20c5.523 0 10-4.477 10-10S5.523 0 0 0h20v20H0Z" />
|
||||
</svg>
|
||||
<div className="grow w-full h-5 bg-white flex flex-col justify-center">
|
||||
<div className="h-px w-full border-t border-dashed border-slate-200" />
|
||||
</div>
|
||||
<svg className="w-5 h-5 fill-white rotate-180" xmlns="http://www.w3.org/2000/svg">
|
||||
<svg
|
||||
className="w-5 h-5 fill-white rotate-180"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path d="M0 20c5.523 0 10-4.477 10-10S5.523 0 0 0h20v20H0Z" />
|
||||
</svg>
|
||||
</div>
|
||||
@@ -344,15 +756,21 @@ function Profile () {
|
||||
<div className="bg-white rounded-b-xl p-5 pt-[22px] pb-10 text-sm space-y-3">
|
||||
<div className="flex justify-between space-x-1">
|
||||
<span className="italic">Validator:</span>
|
||||
<span className="font-medium text-slate-700 text-right">IT17 2207 1010 0504 0006 88</span>
|
||||
<span className="font-medium text-slate-700 text-right">
|
||||
IT17 2207 1010 0504 0006 88
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex justify-between space-x-1">
|
||||
<span className="italic">Recipient:</span>
|
||||
<span className="font-medium text-slate-700 text-right">IT17 2207 1010 0504 0006 88</span>
|
||||
<span className="font-medium text-slate-700 text-right">
|
||||
IT17 2207 1010 0504 0006 88
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex justify-between space-x-1">
|
||||
<span className="italic">Transacion::</span>
|
||||
<span className="font-medium text-slate-700 text-right">145 bytes</span>
|
||||
<span className="italic">Transaction:</span>
|
||||
<span className="font-medium text-slate-700 text-right">
|
||||
145 bytes
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -363,20 +781,35 @@ function Profile () {
|
||||
<button
|
||||
className="btn w-full bg-indigo-500 hover:bg-indigo-600 text-white px-[100px] justify-start"
|
||||
onClick={openRemovePanel}
|
||||
>
|
||||
<svg
|
||||
className="w-4 h-4 fill-current shrink-0"
|
||||
viewBox="0 0 16 16"
|
||||
>
|
||||
<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" />
|
||||
</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">
|
||||
<svg className="w-4 h-4 fill-rose-500 shrink-0" viewBox="0 0 16 16">
|
||||
<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>
|
||||
<span className="ml-2">Update</span>
|
||||
</button>
|
||||
<button className="btn w-full border-slate-200 hover:border-slate-300 text-slate-600 px-[100px] justify-start">
|
||||
<svg className="w-4 h-4 fill-rose-500 shrink-0" viewBox="0 0 16 16">
|
||||
<button
|
||||
className="btn w-full border-slate-200 hover:border-slate-300 text-slate-600 px-[100px] justify-start"
|
||||
onClick={openSharePanel}
|
||||
>
|
||||
<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>
|
||||
<span className="ml-2">Share</span>
|
||||
@@ -389,7 +822,7 @@ function Profile () {
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
export default Profile;
|
||||
@@ -1,70 +1,17 @@
|
||||
import React, { useState } from 'react';
|
||||
|
||||
import { observer } from 'mobx-react-lite';
|
||||
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";
|
||||
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 { store } from '../../store/store';
|
||||
|
||||
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 */}
|
||||
@@ -73,15 +20,22 @@ function Validate () {
|
||||
<div className="relative flex flex-col flex-1 overflow-y-auto overflow-x-hidden">
|
||||
{/* Site header */}
|
||||
<Header sidebarOpen={sidebarOpen} setSidebarOpen={setSidebarOpen} />
|
||||
<main>
|
||||
<main className="relative">
|
||||
<div className="px-4 sm:px-6 lg:px-8 py-8 w-full max-w-9xl mx-auto">
|
||||
<div className="w-fit">
|
||||
{/* Page header */}
|
||||
{/* Page header */}
|
||||
<div className="pb-2.5">
|
||||
{/* Title */}
|
||||
<h1 className="text-2xl md:text-3xl text-slate-800 font-bold">0x28394710234192304719234</h1>
|
||||
<h1 className="text-2xl md:text-3xl text-slate-800 font-bold">
|
||||
0x28394710234192304719234
|
||||
</h1>
|
||||
</div>
|
||||
<Link className="font-normal text-sm text-indigo-500 hover:text-indigo-600" to="/digitalId/validate">Explore -></Link>
|
||||
<Link
|
||||
className="font-normal text-sm text-indigo-500 hover:text-indigo-600"
|
||||
to="/digitalId/validate"
|
||||
>
|
||||
Explore ->
|
||||
</Link>
|
||||
<div className="mb-5 mt-5">
|
||||
<ul className="flex flex-wrap -m-1">
|
||||
<li className="m-1">
|
||||
@@ -106,20 +60,25 @@ function Validate () {
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<ValidateTable setValidatePanelOpen={setValidatePanelOpen}/>
|
||||
<div className="pb-8 border-b border-zinc-200 mt-12">
|
||||
<h1 className="text-2xl md:text-3xl text-slate-800 font-bold">Digiatl ID validation log ✨</h1>
|
||||
<ValidateTable setValidatePanelOpen={setValidatePanelOpen} />
|
||||
<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 => {
|
||||
return <ValidateRoadMap season={item} key={item.id}/>
|
||||
{store.transactionsInfo.map((item) => {
|
||||
return <ValidateRoadMap season={item} key={item.id} />;
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
<ValidatePanel validatePanelOpen={validatePanelOpen} setValidatePanelOpen={setValidatePanelOpen}/>
|
||||
<ValidatePanel
|
||||
validatePanelOpen={validatePanelOpen}
|
||||
setValidatePanelOpen={setValidatePanelOpen}
|
||||
/>
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
export default Validate;
|
||||
|
||||
@@ -1,196 +1,44 @@
|
||||
import React, { useState } from 'react';
|
||||
|
||||
import ValidateRoadMap from "../../partials/validationlog/ValidateRoadMap";
|
||||
import ValidateRoadMap from '../../partials/validationLog/ValidateRoadMap';
|
||||
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";
|
||||
import { store } from '../../store/store';
|
||||
|
||||
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 */}
|
||||
<Sidebar sidebarOpen={sidebarOpen} setSidebarOpen={setSidebarOpen} />
|
||||
{/* Content area */}
|
||||
<div className="relative flex flex-col flex-1 overflow-y-auto overflow-x-hidden">
|
||||
{/* Site header */}
|
||||
<Header sidebarOpen={sidebarOpen} setSidebarOpen={setSidebarOpen} />
|
||||
<main>
|
||||
<div className="px-4 sm:px-6 lg:px-8 py-8 w-full max-w-9xl mx-auto">
|
||||
{/* Page header */}
|
||||
<div className="pb-8 border-b border-zinc-200">
|
||||
{/* Title */}
|
||||
<h1 className="text-2xl md:text-3xl text-slate-800 font-bold">Digiatl ID transaction log ✨</h1>
|
||||
</div>
|
||||
{/*Psosts*/}
|
||||
<div className="max-w-3xl m-auto mt-8">
|
||||
<div className="xl:-translate-x-16 max-w-fit">
|
||||
{/* PostsID */}
|
||||
{logItems.map(item => {
|
||||
return <ValidateRoadMap season={item} key={item.id} />
|
||||
})}
|
||||
{/* Post */}
|
||||
<article className="pt-6">
|
||||
<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 className="flex h-screen overflow-hidden">
|
||||
{/* Sidebar */}
|
||||
<Sidebar sidebarOpen={sidebarOpen} setSidebarOpen={setSidebarOpen} />
|
||||
{/* Content area */}
|
||||
<div className="relative flex flex-col flex-1 overflow-y-auto overflow-x-hidden">
|
||||
{/* Site header */}
|
||||
<Header sidebarOpen={sidebarOpen} setSidebarOpen={setSidebarOpen} />
|
||||
<main>
|
||||
<div className="px-4 sm:px-6 lg:px-8 py-8 w-full max-w-9xl mx-auto">
|
||||
{/* Page header */}
|
||||
<div className="pb-8 border-b border-zinc-200">
|
||||
{/* Title */}
|
||||
<h1 className="text-2xl md:text-3xl text-slate-800 font-bold">
|
||||
Digital ID transaction log ✨
|
||||
</h1>
|
||||
</div>
|
||||
{/*Psosts*/}
|
||||
<div className="max-w-3xl m-auto mt-6">
|
||||
<div className="xl:-translate-x-16 max-w-fit">
|
||||
{/* PostsID */}
|
||||
{store.transactionsInfo.map((item) => {
|
||||
return <ValidateRoadMap season={item} key={item.id} />;
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
export default ValidationLog;
|
||||
|
||||