221 Commits

Author SHA1 Message Date
kandrusyak
a2dd48be65 add settings.json 2022-12-14 15:54:31 +03:00
kandrusyak
bd8268d848 add build 2022-12-12 21:51:58 +03:00
kandrusyak
4ca691608a add Google Analytics 2022-12-12 15:14:07 +03:00
kandrusyak
5939bb4e13 add unlock transaction 2022-12-09 11:53:36 +03:00
kandrusyak
68e665804c add compute fee 2022-12-09 11:24:21 +03:00
kandrusyak
2efc3acd94 add cursor pointer, add server detail animation 2022-12-06 20:12:10 +03:00
kandrusyak
428153a9d9 fix server display name and conf file name 2022-12-06 18:27:02 +03:00
kandrusyak
78f48b240b some fixes 2022-12-06 16:16:12 +03:00
kandrusyak
8bf83aaa5b some fixes 2022-12-05 23:09:54 +03:00
kandrusyak
e0753a0779 fix statuses and dns 2022-12-05 21:18:16 +03:00
kandrusyak
9c331789b3 fix vpn servers 2022-12-05 19:45:45 +03:00
kandrusyak
3e8a0e2233 fix header mistake 2022-12-01 16:21:02 +03:00
kandrusyak
a8bb75b2f5 add prettier 2022-12-01 13:50:14 +03:00
kandrusyak
8e4b6c832e remove mock 2022-12-01 13:44:35 +03:00
kandrusyak
0927c0dca5 fix blank screen 2022-11-27 02:51:35 +03:00
kandrusyak
a555d18417 add vpn and delegates 2022-11-27 02:45:33 +03:00
kandrusyak
ea4d8a4049 Revert "add messages api"
This reverts commit 2210b4ab91.
2022-10-05 17:22:11 +03:00
kandrusyak
1448d3e7da Revert "add messages api"
This reverts commit e07353cd87.
2022-10-05 17:22:07 +03:00
kandrusyak
e07353cd87 add messages api 2022-10-05 16:42:19 +03:00
kandrusyak
2210b4ab91 add messages api 2022-10-05 16:16:44 +03:00
kandrusyak
8e5c0a3edc validate data 2022-09-13 18:10:07 +03:00
kandrusyak
4f73075cf9 share data rework 2022-09-08 13:20:51 +03:00
Kirill Andrusyak
b68ef748ca Merge pull request #59 from franze6/DID-14
Added the ability to share account data
2022-09-07 18:54:07 +03:00
DwCay
200f4f58a7 Added the ability to share account data 2022-08-30 22:49:13 +03:00
kandrusyak
86a6bf013d fix processed status 2022-08-26 15:25:33 +03:00
Kirill Andrusyak
6afa08e5f5 Merge pull request #58 from franze6/DID-13 2022-08-24 20:24:43 +03:00
DwCay
3173ec9342 Fix style for status markers 2022-08-24 19:41:42 +03:00
DuCay
c8352e6537 Merge branch 'master' into DID-13 2022-08-24 17:21:00 +03:00
DwCay
9fbc6423d1 Refactoring code and fix problems display blockchain data 2022-08-24 17:00:43 +03:00
kandrusyak
e4f691ab78 add processed fields 2022-08-24 13:24:10 +03:00
Kirill Andrusyak
446276fadf Merge pull request #57 from franze6/DID-13
Fixed delete and update data account
2022-08-24 10:08:39 +03:00
DwCay
1b574ac347 Fixed delete and update data account 2022-08-24 06:04:21 +03:00
Kirill Andrusyak
0c7db9cd30 Merge pull request #56 from franze6/DID-13
Did 13
2022-08-23 11:36:53 +03:00
DwCay
fc977cc43a Fix decrypted data for blockchain data 2022-08-23 11:17:34 +03:00
DwCay
0a0151d1dd Added location statuses for account data 2022-08-23 05:50:59 +03:00
kandrusyak
369f0e375c add loader 2022-08-22 17:05:05 +03:00
kandrusyak
79ca03823c Change timeout 2022-08-22 15:53:00 +03:00
kandrusyak
49f3ee17a0 tr fix 2022-08-22 15:46:39 +03:00
kandrusyak
841e82e233 update dockerfile 2022-08-17 16:24:49 +03:00
Kirill Andrusyak
2212ea7433 Create docker-image.yml 2022-08-17 15:46:40 +03:00
kandrusyak
f257066d5a blockchain integration 2022-08-17 14:05:49 +03:00
Kirill Andrusyak
027bf0d405 Merge pull request #55 from franze6/DID-12 2022-08-16 17:17:41 +03:00
DwCay
663cfacf63 Removed avatar display in updated and added sender avatar generation in validations 2022-08-16 15:54:55 +03:00
kandrusyak
27ee899402 clean up and bug fixes 2022-08-09 17:52:03 +03:00
kandrusyak
59dd4c9554 fix some bugs 2022-08-09 00:14:21 +03:00
kandrusyak
c659e17344 improve performance 2022-08-08 19:00:56 +03:00
DuCay
49d86ed74b Merge pull request #53 from franze6/DID-12
Changed methods for fetch data transactions and for get passPhrase
2022-08-03 12:04:15 +03:00
DwCay
b2d5df9533 changed methods for encrypt 2022-08-03 12:02:44 +03:00
Daria Golova
0eea3d1ea3 changed userData to accountData 2022-08-03 11:22:07 +03:00
Daria Golova
9686e5245f changed userData to accounData 2022-08-03 11:14:47 +03:00
Daria Golova
1f306b2dce Merge pull request #52 from franze6/DID-11
added data check for the table on Profile page
2022-08-03 10:31:48 +03:00
DwCay
a86dd13e0e Changed methods for fetch data transactions and for get passPhrase 2022-08-03 00:48:32 +03:00
Daria Golova
0e5d7477fc added data check for the table on Profile page 2022-08-02 20:57:10 +03:00
kandrusyak
f395661480 some fixes 2022-08-02 19:11:05 +03:00
kandrusyak
4c334648cb remove links 2022-08-02 18:55:04 +03:00
kandrusyak
344b2c7862 add proxy api 2022-08-01 14:07:23 +03:00
Daria Golova
826f340e9a Merge pull request #51 from franze6/DID-11
added the seed field in the store
2022-07-27 16:24:54 +03:00
Daria Golova
b4bccf2cba added the seed field in the store 2022-07-27 16:20:33 +03:00
Daria Golova
7bb1832d4d added the seed field in the store 2022-07-27 15:58:15 +03:00
Daria Golova
17ac1b04eb Merge pull request #50 from franze6/DID-11
removed the scroll from the input
2022-07-27 15:39:32 +03:00
Daria Golova
e4dc1e961e removed the scroll from the input 2022-07-27 15:39:05 +03:00
Daria Golova
fa198054dd Merge pull request #49 from franze6/DID-11
fixed a bug when deleting elements
2022-07-27 14:31:31 +03:00
Daria Golova
f31c895b8d fixed a bug when deleting elements 2022-07-27 14:28:11 +03:00
Daria Golova
b7be78cf76 Merge pull request #48 from franze6/DID-12
fixed function references
2022-07-26 17:42:56 +03:00
Daria Golova
6d92fde547 fixed function references 2022-07-26 17:39:42 +03:00
DuCay
03bc841894 Merge pull request #47 from franze6/DID-12
Change page signin
2022-07-26 17:18:20 +03:00
DuCay
c24a1fa09d Merge branch 'master' into DID-12 2022-07-26 17:18:14 +03:00
DwCay
57e5dee442 Change page signin 2022-07-26 17:00:39 +03:00
Daria Golova
188e79caf9 Merge pull request #46 from franze6/DID-11
replaced forms with divs and old logo
2022-07-26 14:10:53 +03:00
Daria Golova
e9b21c5c02 replaced forms with divs and old logo 2022-07-26 14:09:48 +03:00
DuCay
75464d81f0 Merge pull request #45 from franze6/DID-12
Did 12
2022-07-26 11:42:10 +03:00
DwCay
fcb7d40ca5 Add method get and save passPhrase. Сorrections in the display of data on the page validationLog 2022-07-26 03:33:11 +03:00
DwCay
f27edb97bb Change methods for new transactions data 2022-07-25 17:55:34 +03:00
Daria Golova
b75a2349c2 Merge pull request #44 from franze6/DID-11
removed the verification of the updating form
2022-07-25 16:47:38 +03:00
Daria Golova
37c9feffe1 removed the verification of the updating form 2022-07-25 16:46:35 +03:00
Daria Golova
fe6bcf8d0f Merge pull request #43 from franze6/DID-11
Добавила проверку заполнения формы изменения параметров профиля
2022-07-21 16:15:02 +03:00
Daria Golova
d7488f8ca9 deleted an extra line 2022-07-21 16:12:23 +03:00
Daria Golova
ffa92ded10 deleted console.log 2022-07-21 16:09:44 +03:00
Daria Golova
68e94201e0 added an update form check 2022-07-21 16:07:40 +03:00
DuCay
020e45ddce Merge pull request #42 from franze6/DID-10
Change fetch Node info data for POST methods
2022-07-21 11:39:37 +03:00
DwCay
8955d846e4 Change fetch Node info data for POST methods 2022-07-21 11:39:07 +03:00
DuCay
d5bc90c818 Merge pull request #41 from franze6/DID-10
Bug fixes when trying to get data on page reload
2022-07-19 23:11:15 +03:00
DuCay
16a2ffca2d Merge branch 'master' into DID-10 2022-07-19 23:11:07 +03:00
DwCay
f932c0bc33 Bug fixes when trying to get data on page reload 2022-07-19 23:09:47 +03:00
Daria Golova
da268d7ecc Merge pull request #40 from franze6/DID-11
Проверка кода, ренейминг
2022-07-18 15:16:30 +03:00
Daria Golova
736e8fc16b deleted settings.json 2022-07-18 15:14:43 +03:00
Daria Golova
774955f131 code review 2022-07-18 15:11:20 +03:00
DuCay
5b20d71a0c Merge pull request #39 from franze6/DID-10
Did 10
2022-07-18 11:31:49 +03:00
DuCay
9714b0add8 Merge branch 'master' into DID-10 2022-07-18 11:31:43 +03:00
DwCay
52eb2a75c1 Fix onBecomeObserved reaction property 2022-07-18 11:27:55 +03:00
DwCay
3c77264fae Fix url 2022-07-18 11:16:02 +03:00
DwCay
429f36b6a6 Refactoring store and association stores into one 2022-07-15 18:54:03 +03:00
Daria Golova
11be69a79b Merge pull request #38 from franze6/DID-9
Исправила url, настроила дефолтный шрифт
2022-07-15 17:26:38 +03:00
Daria Golova
911c13cb87 fixed url, font 2022-07-15 17:22:34 +03:00
kandrusyak
1e9830c8d4 fix merge 2022-07-15 12:10:06 +03:00
Kirill Andrusyak
a8a6355daa Merge pull request #37 from franze6/DID-9
Интеграция страницы Verify с сервером
2022-07-15 12:09:26 +03:00
Kirill Andrusyak
444c94690b Merge branch 'master' into DID-9 2022-07-15 12:09:19 +03:00
Kirill Andrusyak
67133c5414 Merge pull request #36 from franze6/DID-8
Интеграция страницы ValidationLog с сервером
2022-07-15 11:52:25 +03:00
Kirill Andrusyak
f58a94bf24 Merge pull request #35 from franze6/DID-7
Внесла правки на странице Profile
2022-07-15 11:51:01 +03:00
DwCay
9820692cd9 Добавлен адресс аккаунта совершившего транзакцию 2022-07-13 15:39:20 +03:00
Daria Golova
2eeb39abc9 rendered the data in the component 2022-07-13 14:45:17 +03:00
DwCay
5eb4ee16c0 Удален ValidationLogStore 2022-07-13 14:31:27 +03:00
DwCay
bc364d1b85 Исправлен нейминг в store и transactionsStore. Возвращены иконки юзеров на страницу ValidationLog 2022-07-13 14:30:11 +03:00
DwCay
8489bc375c Интеграция страницы ValidationLog с сервером 2022-07-12 19:21:39 +03:00
Daria Golova
b9f795c0e4 done store for shared data 2022-07-12 16:56:44 +03:00
Daria Golova
47dfcf347c added stacking context for the hint 2022-07-11 15:08:45 +03:00
Daria Golova
e837f7cc89 added onblur, fixed seed, moved default values 2022-07-11 15:08:45 +03:00
DuCay
7ad29e8fe0 Merge pull request #34 from franze6/DID-6
Refactoring method saveDataRegistration in store
2022-07-11 11:16:42 +03:00
DwCay
0fb5764a70 Refactoring method saveDataRegistration in store 2022-07-11 11:15:53 +03:00
DuCay
5ebc965a2a Merge pull request #33 from franze6/DID-6
Refactoring in Onboarding steps
2022-07-08 21:24:21 +03:00
DuCay
138047fa10 Merge branch 'master' into DID-6 2022-07-08 21:24:04 +03:00
DwCay
a271da7bf9 Refactoring in Onboarding steps 2022-07-08 21:20:09 +03:00
Kirill Andrusyak
79784cbcee Merge pull request #32 from franze6/DID-7
Создана форма изменения параметров профиля, добавлен функционал для изменения и добавления параметров
2022-07-08 16:32:18 +03:00
Daria Golova
596c44aac3 changed strange IIFE function 2022-07-07 10:19:31 +03:00
Daria Golova
5d17137815 made sending data 2022-07-06 20:22:48 +03:00
Daria Golova
18bf373508 changed the names of the methods 2022-07-06 19:38:09 +03:00
Daria Golova
944c9989e9 fix seed 2022-07-06 19:33:27 +03:00
Daria Golova
202989f374 agreed on form to change and add 2022-07-06 19:33:27 +03:00
Daria Golova
f21d10f830 added prop key, made update form 2022-07-06 19:33:27 +03:00
DuCay
c8604a56ac Merge pull request #31 from franze6/DID-6
Changing data in store to array
2022-07-06 19:27:56 +03:00
DwCay
2d0ae35cc8 Changing data in store to array 2022-07-06 19:27:26 +03:00
DuCay
76f942b90f Merge pull request #30 from franze6/DID-6
Change methods in store
2022-07-06 18:52:22 +03:00
DwCay
f0e0d9479d Change methods in store 2022-07-06 18:51:57 +03:00
DuCay
3403289e0a Merge pull request #29 from franze6/DID-6
New naming for store
2022-07-06 12:59:44 +03:00
DwCay
25fddec6e8 New naming for store 2022-07-06 12:58:53 +03:00
DuCay
1d0cb45024 Merge pull request #28 from franze6/DID-6
Fix naming in store
2022-07-06 12:46:06 +03:00
DwCay
222850dfd9 Fix naming in store 2022-07-06 12:44:53 +03:00
Kirill Andrusyak
8f225752cf Merge pull request #27 from franze6/DID-6
Add method for delete property account
2022-07-06 12:28:46 +03:00
kandrusyak
038657751a add deploy files 2022-07-05 15:18:36 +03:00
kandrusyak
29d7d6fdb8 change endpoint url 2022-07-05 15:12:22 +03:00
DwCay
e44dfee284 Add method for delete property account 2022-07-04 18:02:34 +03:00
Kirill Andrusyak
0f455f126d Merge pull request #26 from franze6/DID-5
Интеграция таблицы страницы Profile с сервером
2022-07-04 10:10:03 +03:00
Daria Golova
0d4f27660a Merge branch 'DID-5' 2022-07-01 17:27:39 +03:00
Daria Golova
9703371f28 made a reference book 2022-07-01 17:16:09 +03:00
Daria Golova
16ca8a1df2 converted user data into Map object 2022-07-01 16:03:21 +03:00
Daria Golova
e883b190a7 converted user data into Map object 2022-07-01 16:01:20 +03:00
Daria Golova
85897a8efe changed name of the method in store.js 2022-06-30 14:50:59 +03:00
Daria Golova
5f85d1696a integrated received data into table 2022-06-30 14:42:59 +03:00
Daria Golova
1c539e5255 made userDataStore 2022-06-30 14:42:59 +03:00
DuCay
bcfc018560 Merge pull request #25 from franze6/DID-4
Did 4
2022-06-30 13:35:58 +03:00
DwCay
e175ca0295 fix naming for post method 2022-06-30 13:35:07 +03:00
DwCay
bac246eac2 fix label name for post request 2022-06-30 13:17:10 +03:00
DwCay
f65c99e86a fix store 2022-06-29 19:35:06 +03:00
DwCay
63439b2da1 Add method post encrypt auth data 2022-06-29 18:47:49 +03:00
Kirill Andrusyak
1d9368d200 Merge pull request #24 from franze6/DID-3
Доработка формы создания поля
2022-06-28 17:01:22 +03:00
kandrusyak
3a4ed9daf9 auth 2022-06-28 16:38:05 +03:00
Daria Golova
54ccd3ed9f fix popup hint 2022-06-23 18:52:19 +03:00
Daria Golova
fe1105e9d6 delete useEffect 2022-06-23 15:28:29 +03:00
Daria Golova
95cc2ac1e0 fix property field, added default value of seed 2022-06-23 15:21:08 +03:00
Daria Golova
b4516ef18e made a popup hint 2022-06-22 19:36:58 +03:00
kandrusyak
d617de75b5 router fix 2022-06-22 14:53:31 +03:00
Kirill Andrusyak
83e5e39d3c Merge pull request #21 from franze6/DID-2
Создание fetch wrapper
2022-06-21 11:47:58 +03:00
Kirill Andrusyak
f89d59e7df Merge branch 'master' into DID-2 2022-06-21 11:47:49 +03:00
Kirill Andrusyak
c944644db0 Merge pull request #23 from franze6/DID-1
Did 1
2022-06-21 11:44:57 +03:00
DwCay
bfdddee46a Add method for get passPhrase and generation hex for account logo 2022-06-18 16:50:32 +03:00
kandrusyak
0da68ddd63 migrate to webpack 2022-06-17 16:56:30 +03:00
Daria Golova
f209ee5f5f added token availability check 2022-06-16 16:05:48 +03:00
Daria Golova
9bef3d9311 fix authorization by token 2022-06-16 15:25:25 +03:00
Daria Golova
632b98a81a added authorization by token 2022-06-16 14:30:41 +03:00
DwCay
eeaabeebf3 Add method for get passPhrase 2022-06-15 17:41:02 +03:00
Daria Golova
81f5ec2741 fix methods 2022-06-15 14:36:23 +03:00
Daria Golova
3fcda54070 fix wrapper 2022-06-15 14:21:39 +03:00
Daria Golova
49aff14a80 create fetch wrapper 2022-06-14 13:53:28 +03:00
DwCay
da04efbf80 Add registration store 2022-06-14 13:13:58 +03:00
DuCay
541c5988e9 Merge pull request #20 from franze6/Deleting_elements
Delete Onboarding and Component from Sidebar
2022-06-02 15:53:43 +03:00
DwCay
cfa5af78c0 Delete Onboarding and Component from Sidebar 2022-06-02 15:53:06 +03:00
DuCay
fc4d9fb897 Merge pull request #19 from franze6/Validation_merged
Update Validate Panel
2022-06-02 15:35:15 +03:00
DwCay
ed5565eb17 Update Validate Panel 2022-06-02 15:34:20 +03:00
DuCay
99512491fa Merge pull request #18 from franze6/Onboarding_steps
Start window Onboarding1
2022-06-02 14:40:24 +03:00
DwCay
24a66478d6 Start window Onboarding1 2022-06-02 14:27:04 +03:00
DuCay
9484b0bda9 Merge pull request #17 from franze6/Validation_merged
Fix errors and styling
2022-06-01 20:46:49 +03:00
DwCay
885963be45 Fix errors and styling 2022-06-01 20:45:14 +03:00
DuCay
e144e50a40 Merge pull request #16 from franze6/Onboarding_steps
Fix routing link in onboarding steps
2022-06-01 17:59:40 +03:00
DwCay
16f9a52a41 Fix routing link in onboarding steps 2022-06-01 17:58:51 +03:00
DuCay
5e74f2bc0b Merge pull request #15 from franze6/Onboarding_steps
Onboarding fix styling
2022-06-01 17:36:25 +03:00
DuCay
fa5ddbf64a Merge branch 'master' into Onboarding_steps 2022-06-01 17:36:15 +03:00
DwCay
c45b7c5e4d Onboarding fix styling 2022-06-01 17:33:20 +03:00
Daria Golova
606223216f Merge pull request #13 from franze6/Profile-Page
fix profile page
2022-06-01 17:25:45 +03:00
Daria Golova
c41bed05fd Merge pull request #14 from franze6/Verify-Page
fix verify page
2022-06-01 17:25:34 +03:00
Daria Golova
b71dccbd0e fix field on sidepanel 2022-06-01 17:18:22 +03:00
Daria Golova
264a908352 fix paddings 2022-06-01 16:51:32 +03:00
Daria Golova
36eb756be0 fix key 2022-06-01 16:21:14 +03:00
DuCay
f74293b1f4 Merge pull request #12 from franze6/Onboarding_steps
Onboarding2 fix name for form
2022-06-01 15:57:57 +03:00
DwCay
095c5e236e Onboarding2 fix name for form 2022-06-01 15:56:09 +03:00
DuCay
f3dcbdab49 Merge pull request #11 from franze6/Shared_data_
Shared data
2022-06-01 14:45:05 +03:00
DwCay
3236f2ae94 Save avatar svg in shared data for header 2022-06-01 10:27:49 +03:00
DwCay
0d127aa5fa Add shared data in routes 2022-06-01 07:25:39 +03:00
DwCay
ac18be77a7 Add shared data page 2022-06-01 07:25:39 +03:00
Kirill Andrusyak
568543bba5 Merge pull request #10 from franze6/Deleting_elements 2022-06-01 00:50:02 +03:00
DwCay
3b62d188c1 Merge branch 'deleting_elements'
# Conflicts:
#	src/pages/digitalId/Validate.jsx
2022-05-31 23:58:51 +03:00
DwCay
de11c6be0f Conflict fix 2022-05-31 23:31:20 +03:00
Daria Golova
5b1ff31e01 changed the array, added props 2022-05-31 23:30:16 +03:00
Daria Golova
03bb781b5a created ablock with a verified data 2022-05-31 23:30:16 +03:00
Daria Golova
981d62b849 rename sizes 2022-05-31 23:30:16 +03:00
Daria Golova
883f173c12 fix left sidebar 2022-05-31 23:30:16 +03:00
Daria Golova
709f668697 add other forms 2022-05-31 23:30:16 +03:00
Daria Golova
3e5ef4f128 fix form for adding fields 2022-05-31 23:30:16 +03:00
Daria Golova
d86c118b21 create add field form 2022-05-31 23:30:16 +03:00
Daria Golova
4179cd703d create table 2022-05-31 23:30:16 +03:00
Kirill Andrusyak
20221b497b Merge pull request #8 from franze6/Validation_merged
Validation merged
2022-05-31 19:47:08 +03:00
Kirill Andrusyak
9bdbd396e8 Merge pull request #9 from franze6/Verify-Page
Verify page
2022-05-31 19:46:20 +03:00
Daria Golova
c7d797b2af changed the array, added props 2022-05-31 16:31:25 +03:00
DwCay
bc71ea6cb9 Returned authorization 2022-05-31 15:55:54 +03:00
DwCay
8dd57625fd Merge branch 'Validation_log_and_validate_pages'
# Conflicts:
#	src/pages/digitalId/Validate.jsx
#	src/pages/digitalId/ValidationLog.jsx
2022-05-31 14:26:20 +03:00
DwCay
ec700318ae Conflict fix 2022-05-31 13:58:27 +03:00
Daria Golova
bcd7f89dee created ablock with a verified data 2022-05-31 11:26:56 +03:00
Kirill Andrusyak
0de76771ac Merge pull request #6 from franze6/Profile-Page 2022-05-31 10:36:10 +03:00
DwCay
3cd337d589 Removing redundant components 2022-05-30 16:23:36 +03:00
Daria Golova
3f3a56c305 rename sizes 2022-05-30 16:17:11 +03:00
Daria Golova
b40b59af3f fix left sidebar 2022-05-30 16:07:22 +03:00
DwCay
b98c4db02d first deleting_elements commit 2022-05-30 12:08:21 +03:00
Daria Golova
a5a046f911 add other forms 2022-05-27 17:36:06 +03:00
Daria Golova
d31a2f09d5 fix form for adding fields 2022-05-27 12:35:36 +03:00
DwCay
5fca3bdc4e Naming fix 2022-05-26 22:34:07 +03:00
DwCay
e6142b1402 Update ValidationSeasonItem 2022-05-26 20:35:29 +03:00
DwCay
df6419bfff Add page Validate and update ValidationLog 2022-05-26 20:04:24 +03:00
Daria Golova
99d235f5e7 create add field form 2022-05-26 18:05:07 +03:00
Daria Golova
180961ec20 create table 2022-05-26 15:59:34 +03:00
kandrusyak
c4c7b10b99 fix mistake 2022-05-26 13:14:47 +03:00
Kirill Andrusyak
79bed4e69d Merge pull request #4 from franze6/Profile-table-item
Элемент таблицы Digital ID - Profile
2022-05-26 13:13:36 +03:00
DwCay
13839cf67c Add page ValidationLog 2022-05-26 00:47:06 +03:00
308 changed files with 22053 additions and 36351 deletions

64
.github/workflows/docker-image.yml vendored Normal file
View 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

3
.gitignore vendored
View File

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

19
.prettierrc Normal file
View 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
View 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

View File

@@ -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
View File

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 916 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 912 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 623 B

View 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

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View 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

View 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

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

BIN
dist/favicon.ico vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

1
dist/index.html vendored Normal file
View 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

File diff suppressed because one or more lines are too long

96
dist/main.3ab1a28d.js.LICENSE.txt vendored Normal file
View 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
View File

@@ -0,0 +1,3 @@
{
"API_URL": "https://tn-alpha.idntty.org:8080/api/"
}

View File

@@ -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>

18846
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,28 +1,68 @@
{
"name": "mosaic-react",
"version": "0.1.0",
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview"
},
"dependencies": {
"@tailwindcss/forms": "^0.4.0",
"chart.js": "^3.5.0",
"chartjs-adapter-moment": "^1.0.0",
"moment": "^2.29.1",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-flatpickr": "^3.10.7",
"react-router-dom": "^6.2.1",
"react-transition-group": "^4.4.1"
},
"devDependencies": {
"@vitejs/plugin-react": "^1.0.7",
"autoprefixer": "^10.4.2",
"postcss": "^8.4.5",
"sass": "^1.49.0",
"tailwindcss": "^3.0.18",
"vite": "^2.7.2"
}
}
{
"name": "mosaic-react",
"version": "0.1.0",
"scripts": {
"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",
"sodium-universal": "^3.1.0",
"stream-browserify": "^3.0.0",
"url": "^0.11.0",
"util": "^0.12.4"
},
"devDependencies": {
"@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",
"postcss-loader": "^7.0.0",
"sass": "^1.52.3",
"sass-loader": "^13.0.0",
"style-loader": "^3.3.1",
"tailwindcss": "^3.0.18",
"webpack": "^5.73.0",
"webpack-cli": "^4.10.0",
"webpack-dev-server": "^4.9.2"
},
"babel": {
"presets": [
"@babel/env",
"@babel/react"
]
},
"browser": {
"fs": false
}
}

View File

@@ -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

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

19
public/index.html Normal file
View 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
View File

@@ -0,0 +1,3 @@
{
"API_URL": "https://tn-alpha.idntty.org:8080/api/"
}

View File

@@ -1,179 +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 Customers from './pages/ecommerce/Customers';
import Orders from './pages/ecommerce/Orders';
import Invoices from './pages/ecommerce/Invoices';
import Shop from './pages/ecommerce/Shop';
import Shop2 from './pages/ecommerce/Shop2';
import Product from './pages/ecommerce/Product';
import Cart from './pages/ecommerce/Cart';
import Cart2 from './pages/ecommerce/Cart2';
import Cart3 from './pages/ecommerce/Cart3';
import Pay from './pages/ecommerce/Pay';
import Campaigns from './pages/Campaigns';
import UsersTabs from './pages/community/UsersTabs';
import UsersTiles from './pages/community/UsersTiles';
import Profile from './pages/community/Profile';
import Feed from './pages/community/Feed';
import Forum from './pages/community/Forum';
import ForumPost from './pages/community/ForumPost';
import Meetups from './pages/community/Meetups';
import MeetupsPost from './pages/community/MeetupsPost';
import CreditCards from './pages/finance/CreditCards';
import Transactions from './pages/finance/Transactions';
import TransactionDetails from './pages/finance/TransactionDetails';
import JobListing from './pages/job/JobListing';
import JobPost from './pages/job/JobPost';
import CompanyProfile from './pages/job/CompanyProfile';
import Messages from './pages/Messages';
import TasksKanban from './pages/tasks/TasksKanban';
import TasksList from './pages/tasks/TasksList';
import Inbox from './pages/Inbox';
import Calendar from './pages/Calendar';
import Account from './pages/settings/Account';
import Notifications from './pages/settings/Notifications';
import Apps from './pages/settings/Apps';
import Plans from './pages/settings/Plans';
import Billing from './pages/settings/Billing';
import Feedback from './pages/settings/Feedback';
import Changelog from './pages/utility/Changelog';
import Roadmap from './pages/utility/Roadmap';
import Faqs from './pages/utility/Faqs';
import EmptyState from './pages/utility/EmptyState';
import PageNotFound from './pages/utility/PageNotFound';
import KnowledgeBase from './pages/utility/KnowledgeBase';
import Signin from './pages/Signin';
import Signup from './pages/Signup';
import ResetPassword from './pages/ResetPassword';
import Onboarding01 from './pages/Onboarding01';
import Onboarding02 from './pages/Onboarding02';
import Onboarding03 from './pages/Onboarding03';
import Onboarding04 from './pages/Onboarding04';
import ButtonPage from './pages/component/ButtonPage';
import FormPage from './pages/component/FormPage';
import DropdownPage from './pages/component/DropdownPage';
import AlertPage from './pages/component/AlertPage';
import ModalPage from './pages/component/ModalPage';
import PaginationPage from './pages/component/PaginationPage';
import TabsPage from './pages/component/TabsPage';
import BreadcrumbPage from './pages/component/BreadcrumbPage';
import BadgePage from './pages/component/BadgePage';
import AvatarPage from './pages/component/AvatarPage';
import TooltipPage from './pages/component/TooltipPage';
import AccordionPage from './pages/component/AccordionPage';
import IconsPage from './pages/component/IconsPage';
import Onboarding1 from "./pages/Onboarding1";
import Onboarding2 from "./pages/Onboarding2";
import Onboarding3 from "./pages/Onboarding3";
import Onboarding4 from "./pages/Onboarding4";
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="/ecommerce/customers" element={<Customers />} />
<Route path="/ecommerce/orders" element={<Orders />} />
<Route path="/ecommerce/invoices" element={<Invoices />} />
<Route path="/ecommerce/shop" element={<Shop />} />
<Route path="/ecommerce/shop-2" element={<Shop2 />} />
<Route path="/ecommerce/product" element={<Product />} />
<Route path="/ecommerce/cart" element={<Cart />} />
<Route path="/ecommerce/cart-2" element={<Cart2 />} />
<Route path="/ecommerce/cart-3" element={<Cart3 />} />
<Route path="/ecommerce/pay" element={<Pay />} />
<Route path="/campaigns" element={<Campaigns />} />
<Route path="/community/users-tabs" element={<UsersTabs />} />
<Route path="/community/users-tiles" element={<UsersTiles />} />
<Route path="/community/profile" element={<Profile />} />
<Route path="/community/feed" element={<Feed />} />
<Route path="/community/forum" element={<Forum />} />
<Route path="/community/forum-post" element={<ForumPost />} />
<Route path="/community/meetups" element={<Meetups />} />
<Route path="/community/meetups-post" element={<MeetupsPost />} />
<Route path="/finance/cards" element={<CreditCards />} />
<Route path="/finance/transactions" element={<Transactions />} />
<Route path="/finance/transaction-details" element={<TransactionDetails />} />
<Route path="/job/job-listing" element={<JobListing />} />
<Route path="/job/job-post" element={<JobPost />} />
<Route path="/job/company-profile" element={<CompanyProfile />} />
<Route path="/messages" element={<Messages />} />
<Route path="/tasks/kanban" element={<TasksKanban />} />
<Route path="/tasks/list" element={<TasksList />} />
<Route path="/inbox" element={<Inbox />} />
<Route path="/calendar" element={<Calendar />} />
<Route path="/settings/account" element={<Account />} />
<Route path="/settings/notifications" element={<Notifications />} />
<Route path="/settings/apps" element={<Apps />} />
<Route path="/settings/plans" element={<Plans />} />
<Route path="/settings/billing" element={<Billing />} />
<Route path="/settings/feedback" element={<Feedback />} />
<Route path="/utility/changelog" element={<Changelog />} />
<Route path="/utility/roadmap" element={<Roadmap />} />
<Route path="/utility/faqs" element={<Faqs />} />
<Route path="/utility/empty-state" element={<EmptyState />} />
<Route path="/utility/404" element={<PageNotFound />} />
<Route path="/utility/knowledge-base" element={<KnowledgeBase />} />
<Route path="/signin" element={<Signin />} />
<Route path="/signup" element={<Signup />} />
<Route path="/reset-password" element={<ResetPassword />} />
<Route path="/onboarding-01" element={<Onboarding01 />} />
<Route path="/onboarding-02" element={<Onboarding02 />} />
<Route path="/onboarding-03" element={<Onboarding03 />} />
<Route path="/onboarding-04" element={<Onboarding04 />} />
<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="/component/form" element={<FormPage />} />
<Route path="/component/dropdown" element={<DropdownPage />} />
<Route path="/component/alert" element={<AlertPage />} />
<Route path="/component/modal" element={<ModalPage />} />
<Route path="/component/pagination" element={<PaginationPage />} />
<Route path="/component/tabs" element={<TabsPage />} />
<Route path="/component/breadcrumb" element={<BreadcrumbPage />} />
<Route path="/component/badge" element={<BadgePage />} />
<Route path="/component/avatar" element={<AvatarPage />} />
<Route path="/component/tooltip" element={<TooltipPage />} />
<Route path="/component/accordion" element={<AccordionPage />} />
<Route path="/component/icons" element={<IconsPage />} />
<Route path="*" element={<PageNotFound />} />
<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
View File

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

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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();
}
},
});

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -1,79 +0,0 @@
import React from 'react';
function Banner({
children,
className,
type,
open,
setOpen
}) {
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-500';
case 'error':
return 'bg-rose-500';
case 'success':
return 'bg-emerald-500';
default:
return 'bg-indigo-500';
}
};
return (
<>
{open &&
<div className={className}>
<div className={`px-4 py-2 rounded-sm text-sm text-white ${typeColor(type)}`}>
<div className="flex w-full justify-between items-start">
<div className="flex">
{typeIcon(type)}
<div className="font-medium">
{children}
</div>
</div>
<button className="opacity-70 hover:opacity-80 ml-3 mt-[3px]" onClick={() => setOpen(false)}>
<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>
}
</>
);
}
export default Banner;

View File

@@ -1,79 +0,0 @@
import React from 'react';
function Banner2({
children,
className,
type,
open,
setOpen
}) {
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';
}
};
return (
<>
{open &&
<div className={className}>
<div className={`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={() => setOpen(false)}>
<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>
}
</>
);
}
export default Banner2;

View File

@@ -1,116 +0,0 @@
import React, { useState, useRef, useEffect } from 'react';
import Transition from '../utils/Transition';
function DateSelect() {
const options = [
{
id: 0,
period: 'Today'
},
{
id: 1,
period: 'Last 7 Days'
},
{
id: 2,
period: 'Last Month'
},
{
id: 3,
period: 'Last 12 Months'
},
{
id: 4,
period: 'All Time'
}
];
const [dropdownOpen, setDropdownOpen] = useState(false);
const [selected, setSelected] = useState(2);
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">
<button
ref={trigger}
className="btn justify-between min-w-44 bg-white border-slate-200 hover:border-slate-300 text-slate-500 hover:text-slate-600"
aria-label="Select date range"
aria-haspopup="true"
onClick={() => setDropdownOpen(!dropdownOpen)}
aria-expanded={dropdownOpen}
>
<span className="flex items-center">
<svg className="w-4 h-4 fill-current text-slate-500 shrink-0 mr-2" 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>
<span>{options[selected].period}</span>
</span>
<svg className="shrink-0 ml-1 fill-current text-slate-400" width="11" height="7" viewBox="0 0 11 7">
<path d="M5.4 6.8L0 1.4 1.4 0l4 4 4-4 1.4 1.4z" />
</svg>
</button>
<Transition
show={dropdownOpen}
tag="div"
className="z-10 absolute top-full right-0 w-full bg-white border border-slate-200 py-1.5 rounded shadow-lg overflow-hidden mt-1"
enter="transition ease-out duration-100 transform"
enterStart="opacity-0 -translate-y-2"
enterEnd="opacity-100 translate-y-0"
leave="transition ease-out duration-100"
leaveStart="opacity-100"
leaveEnd="opacity-0"
>
<div
ref={dropdown}
className="font-medium text-sm text-slate-600"
onFocus={() => setDropdownOpen(true)}
onBlur={() => setDropdownOpen(false)}
>
{
options.map(option => {
return (
<button
key={option.id}
tabIndex="0"
className={`flex items-center w-full hover:bg-slate-50 py-1 px-3 cursor-pointer ${option.id === selected && 'text-indigo-500'}`}
onClick={() => { setSelected(option.id); setDropdownOpen(false); }}
>
<svg className={`shrink-0 mr-2 fill-current text-indigo-500 ${option.id !== selected && 'invisible'}`} width="12" height="9" viewBox="0 0 12 9">
<path d="M10.28.28L3.989 6.575 1.695 4.28A1 1 0 00.28 5.695l3 3a1 1 0 001.414 0l7-7A1 1 0 0010.28.28z" />
</svg>
<span>{option.period}</span>
</button>
)
})
}
</div>
</Transition>
</div>
);
}
export default DateSelect;

View File

@@ -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;

View File

@@ -1,113 +0,0 @@
import React, { useState, useRef, useEffect } from 'react';
import Transition from '../utils/Transition';
function DropdownClassic() {
const options = [
{
id: 0,
period: 'Today'
},
{
id: 1,
period: 'Last 7 Days'
},
{
id: 2,
period: 'Last Month'
},
{
id: 3,
period: 'Last 12 Months'
},
{
id: 4,
period: 'All Time'
}
];
const [dropdownOpen, setDropdownOpen] = useState(false);
const [selected, setSelected] = useState(2);
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 justify-between min-w-44 bg-white border-slate-200 hover:border-slate-300 text-slate-500 hover:text-slate-600"
aria-label="Select date range"
aria-haspopup="true"
onClick={() => setDropdownOpen(!dropdownOpen)}
aria-expanded={dropdownOpen}
>
<span className="flex items-center">
<span>{options[selected].period}</span>
</span>
<svg className="shrink-0 ml-1 fill-current text-slate-400" width="11" height="7" viewBox="0 0 11 7">
<path d="M5.4 6.8L0 1.4 1.4 0l4 4 4-4 1.4 1.4z" />
</svg>
</button>
<Transition
show={dropdownOpen}
tag="div"
className="z-10 absolute top-full left-0 w-full bg-white border border-slate-200 py-1.5 rounded shadow-lg overflow-hidden mt-1"
enter="transition ease-out duration-100 transform"
enterStart="opacity-0 -translate-y-2"
enterEnd="opacity-100 translate-y-0"
leave="transition ease-out duration-100"
leaveStart="opacity-100"
leaveEnd="opacity-0"
>
<div
ref={dropdown}
className="font-medium text-sm text-slate-600"
onFocus={() => setDropdownOpen(true)}
onBlur={() => setDropdownOpen(false)}
>
{
options.map(option => {
return (
<button
key={option.id}
tabIndex="0"
className={`flex items-center w-full hover:bg-slate-50 py-1 px-3 cursor-pointer ${option.id === selected && 'text-indigo-500'}`}
onClick={() => { setSelected(option.id); setDropdownOpen(false); }}
>
<svg className={`shrink-0 mr-2 fill-current text-indigo-500 ${option.id !== selected && 'invisible'}`} width="12" height="9" viewBox="0 0 12 9">
<path d="M10.28.28L3.989 6.575 1.695 4.28A1 1 0 00.28 5.695l3 3a1 1 0 001.414 0l7-7A1 1 0 0010.28.28z" />
</svg>
<span>{option.period}</span>
</button>
)
})
}
</div>
</Transition>
</div>
);
}
export default DropdownClassic;

View File

@@ -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;

View File

@@ -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;

View File

@@ -1,109 +0,0 @@
import React, { useState, useRef, useEffect } from 'react';
import Transition from '../utils/Transition';
function DropdownFull() {
const options = [
{
id: 0,
period: 'Most Popular'
},
{
id: 1,
period: 'Newest'
},
{
id: 2,
period: 'Lowest Price'
},
{
id: 3,
period: 'Highest Price'
}
];
const [dropdownOpen, setDropdownOpen] = useState(false);
const [selected, setSelected] = useState(0);
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 w-full">
<button
ref={trigger}
className="btn w-full justify-between min-w-44 bg-white border-slate-200 hover:border-slate-300 text-slate-500 hover:text-slate-600"
aria-label="Select date range"
aria-haspopup="true"
onClick={() => setDropdownOpen(!dropdownOpen)}
aria-expanded={dropdownOpen}
>
<span className="flex items-center">
<span>{options[selected].period}</span>
</span>
<svg className="shrink-0 ml-1 fill-current text-slate-400" width="11" height="7" viewBox="0 0 11 7">
<path d="M5.4 6.8L0 1.4 1.4 0l4 4 4-4 1.4 1.4z" />
</svg>
</button>
<Transition
show={dropdownOpen}
tag="div"
className="z-10 absolute top-full left-0 w-full bg-white border border-slate-200 py-1.5 rounded shadow-lg overflow-hidden mt-1"
enter="transition ease-out duration-100 transform"
enterStart="opacity-0 -translate-y-2"
enterEnd="opacity-100 translate-y-0"
leave="transition ease-out duration-100"
leaveStart="opacity-100"
leaveEnd="opacity-0"
>
<div
ref={dropdown}
className="font-medium text-sm text-slate-600 divide-y divide-slate-200"
onFocus={() => setDropdownOpen(true)}
onBlur={() => setDropdownOpen(false)}
>
{
options.map(option => {
return (
<button
key={option.id}
tabIndex="0"
className={`flex items-center justify-between w-full hover:bg-slate-50 py-2 px-3 cursor-pointer ${option.id === selected && 'text-indigo-500'}`}
onClick={() => { setSelected(option.id); setDropdownOpen(false); }}
>
<span>{option.period}</span>
<svg className={`shrink-0 mr-2 fill-current text-indigo-500 ${option.id !== selected && 'invisible'}`} width="12" height="9" viewBox="0 0 12 9">
<path d="M10.28.28L3.989 6.575 1.695 4.28A1 1 0 00.28 5.695l3 3a1 1 0 001.414 0l7-7A1 1 0 0010.28.28z" />
</svg>
</button>
)
})
}
</div>
</Transition>
</div>
);
}
export default DropdownFull;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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={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="/settings"
<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="/signin"
onClick={() => setDropdownOpen(!dropdownOpen)}
to="/"
onClick={() => logOut()}
>
Sign Out
</Link>
@@ -94,7 +116,7 @@ function DropdownProfile({
</div>
</Transition>
</div>
)
}
);
});
export default DropdownProfile;
export default DropdownProfile;

View File

@@ -1,90 +0,0 @@
import React, { useState, useRef, useEffect } from 'react';
import Transition from '../utils/Transition';
function DropdownSort({
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="inline-flex justify-center items-center group"
aria-haspopup="true"
onClick={() => setDropdownOpen(!dropdownOpen)}
aria-expanded={dropdownOpen}
>
<div className="flex items-center truncate">
<span className="truncate font-medium text-indigo-500 group-hover:text-indigo-600">Newest</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 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>
<a
className="font-medium text-sm text-slate-600 hover:text-slate-800 flex items-center py-1 px-3"
href="#0"
onClick={() => setDropdownOpen(!dropdownOpen)}
>
Oldest
</a>
</li>
<li>
<a
className="font-medium text-sm text-slate-600 hover:text-slate-800 flex items-center py-1 px-3"
href="#0"
onClick={() => setDropdownOpen(!dropdownOpen)}
>
Popular
</a>
</li>
</ul>
</div>
</Transition>
</div>
);
}
export default DropdownSort;

View File

@@ -1,110 +0,0 @@
import React, { useState, useRef, useEffect } from 'react';
import Transition from '../utils/Transition';
import DropdownImage from '../images/user-avatar-32.png';
import DropdownImage01 from '../images/channel-01.png';
import DropdownImage02 from '../images/channel-02.png';
import DropdownImage03 from '../images/channel-03.png';
function DropdownSwitch({
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">
<button
ref={trigger}
className="grow flex items-center truncate"
aria-haspopup="true"
onClick={() => setDropdownOpen(!dropdownOpen)}
aria-expanded={dropdownOpen}
>
<img className="w-8 h-8 rounded-full mr-2" src={DropdownImage} width="32" height="32" alt="Group 01" />
<div className="truncate">
<span className="text-sm font-medium">Acme Inc.</span>
</div>
<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>
</button>
<Transition
className={`origin-top-right z-10 absolute top-full min-w-60 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"
>
<ul
ref={dropdown}
onFocus={() => setDropdownOpen(true)}
onBlur={() => setDropdownOpen(false)}
>
<li>
<a className="font-medium text-sm text-slate-600 hover:text-slate-800 block py-1.5 px-3" href="#0" onClick={() => setDropdownOpen(false)}>
<div className="flex items-center justify-between">
<div className="grow flex items-center truncate">
<img className="w-7 h-7 rounded-full mr-2" src={DropdownImage01} width="28" height="28" alt="Channel 01" />
<div className="truncate">Acme Inc.</div>
</div>
<svg className="w-3 h-3 shrink-0 fill-current text-indigo-500 ml-1" 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>
</div>
</a>
</li>
<li>
<a className="font-medium text-sm text-slate-600 hover:text-slate-800 block py-1.5 px-3" href="#0" onClick={() => setDropdownOpen(false)}>
<div className="flex items-center justify-between">
<div className="grow flex items-center truncate">
<img className="w-7 h-7 rounded-full mr-2" src={DropdownImage02} width="28" height="28" alt="Channel 02" />
<div className="truncate">Acme Limited</div>
</div>
</div>
</a>
</li>
<li>
<a className="font-medium text-sm text-slate-600 hover:text-slate-800 block py-1.5 px-3" href="#0" onClick={() => setDropdownOpen(false)}>
<div className="flex items-center justify-between">
<div className="grow flex items-center truncate">
<img className="w-7 h-7 rounded-full mr-2" src={DropdownImage03} width="28" height="28" alt="Channel 03" />
<div className="truncate">Acme Srl</div>
</div>
</div>
</a>
</li>
</ul>
</Transition>
</div>
)
}
export default DropdownSwitch;

View File

@@ -1,20 +1,27 @@
import React, { useState, useRef, useEffect } from 'react';
import Transition from '../utils/Transition';
function DropdownTransaction({
align
}) {
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;
if (
!dropdownOpen ||
dropdown.current.contains(target) ||
trigger.current.contains(target)
)
return;
setDropdownOpen(false);
};
document.addEventListener('click', clickHandler);
@@ -37,12 +44,17 @@ function DropdownTransaction({
ref={trigger}
className="inline-flex justify-center items-center group"
aria-haspopup="true"
onClick={() => setDropdownOpen(!dropdownOpen)}
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">My Personal Account</span>
<svg className="w-3 h-3 shrink-0 ml-1 fill-current text-slate-400" viewBox="0 0 12 12">
<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>
@@ -60,25 +72,27 @@ function DropdownTransaction({
leaveStart="opacity-100"
leaveEnd="opacity-0"
>
<div ref={dropdown} onFocus={() => setDropdownOpen(true)} onBlur={() => setDropdownOpen(false)}>
<div
ref={dropdown}
onFocus={() => setDropdownOpen(true)}
onBlur={() => setDropdownOpen(false)}
>
<ul>
<li>
<a
className="font-medium text-sm text-slate-600 hover:text-slate-800 flex items-center py-1 px-3"
href="#0"
onClick={() => setDropdownOpen(!dropdownOpen)}
<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')}
>
Business Account
</a>
Voiting
</span>
</li>
<li>
<a
className="font-medium text-sm text-slate-600 hover:text-slate-800 flex items-center py-1 px-3"
href="#0"
onClick={() => setDropdownOpen(!dropdownOpen)}
<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')}
>
Family Account
</a>
Unlocking
</span>
</li>
</ul>
</div>
@@ -87,4 +101,4 @@ function DropdownTransaction({
);
}
export default DropdownTransaction;
export default DropdownTransaction;

31
src/components/Filters.js Normal file
View 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>
);
};

View 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
);

View File

@@ -1,80 +0,0 @@
import React, { useRef, useEffect } from 'react';
import Transition from '../utils/Transition';
function ModalAction({
children,
id,
modalOpen,
setModalOpen
}) {
const modalContent = 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);
});
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-center my-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 rounded shadow-lg overflow-auto max-w-lg w-full max-h-full">
<div className="p-6">
<div className="relative">
{/* Close button */}
<button className="absolute top-0 right-0 text-slate-400 hover:text-slate-500" onClick={(e) => { e.stopPropagation(); setModalOpen(false); }}>
<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>
{children}
</div>
</div>
</div>
</Transition>
</>
);
}
export default ModalAction;

View File

@@ -1,82 +0,0 @@
import React, { useRef, useEffect } from 'react';
import Transition from '../utils/Transition';
function ModalBasic({
children,
id,
title,
modalOpen,
setModalOpen
}) {
const modalContent = 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);
});
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-center my-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 rounded shadow-lg overflow-auto max-w-lg w-full max-h-full">
{/* Modal header */}
<div className="px-5 py-3 border-b border-slate-200">
<div className="flex justify-between items-center">
<div className="font-semibold text-slate-800">{title}</div>
<button className="text-slate-400 hover:text-slate-500" onClick={(e) => { e.stopPropagation(); setModalOpen(false); }}>
<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>
{children}
</div>
</Transition>
</>
);
}
export default ModalBasic;

View File

@@ -1,69 +0,0 @@
import React, { useRef, useEffect } from 'react';
import Transition from '../utils/Transition';
function ModalBlank({
children,
id,
modalOpen,
setModalOpen
}) {
const modalContent = 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);
});
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-center my-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 rounded shadow-lg overflow-auto max-w-lg w-full max-h-full">
{children}
</div>
</Transition>
</>
);
}
export default ModalBlank;

View File

@@ -1,84 +0,0 @@
import React, { useRef, useEffect } from 'react';
import Transition from '../utils/Transition';
function ModalCookies({
children,
id,
title,
modalOpen,
setModalOpen
}) {
const modalContent = 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);
});
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-center my-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 rounded shadow-lg overflow-auto max-w-lg w-full max-h-full">
<div className="p-5">
{/* Modal header */}
<div className="mb-2">
<div className="flex justify-between items-center">
<div className="text-lg font-semibold text-slate-800">{title}</div>
<button className="text-slate-400 hover:text-slate-500" onClick={(e) => { e.stopPropagation(); setModalOpen(false); }}>
<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>
{children}
</div>
</div>
</Transition>
</>
);
}
export default ModalCookies;

View File

@@ -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;

View File

@@ -1,69 +0,0 @@
import React from 'react';
function Notification({
children,
className,
type,
open,
setOpen
}) {
const typeIcon = (type) => {
switch (type) {
case 'warning':
return (
<svg className="w-4 h-4 shrink-0 fill-current text-amber-500 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 text-rose-500 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 text-emerald-500 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 text-indigo-500 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>
);
}
};
return (
<>
{open &&
<div className={className}>
<div className="inline-flex flex-col max-w-lg px-4 py-2 rounded-sm text-sm bg-white shadow-lg border border-slate-200 text-slate-600">
<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={() => setOpen(false)}>
<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 className="text-right mt-1">
<a className="font-medium text-indigo-500 hover:text-indigo-600" href="#0">Action -&gt;</a>
</div>
</div>
</div>
}
</>
);
}
export default Notification;

View 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>
));

View File

@@ -1,20 +1,49 @@
import React from 'react';
import cn from 'classnames';
function PaginationClassic() {
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">
<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">
<a className="btn bg-white border-slate-200 text-slate-300 cursor-not-allowed" href="#0" disabled>&lt;- Previous</a>
<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}
>
&lt;- Previous
</button>
</li>
<li className="ml-3 first:ml-0">
<a className="btn bg-white border-slate-200 hover:border-slate-300 text-indigo-500" href="#0">Next -&gt;</a>
<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 -&gt;
</button>
</li>
</ul>
</nav>
<div className="text-sm text-slate-500 text-center sm:text-left">
Showing <span className="font-medium text-slate-600">1</span> to <span className="font-medium text-slate-600">10</span> of <span className="font-medium text-slate-600">467</span> results
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>
);

View File

@@ -1,45 +0,0 @@
import React from 'react';
function PaginationNumeric() {
return (
<div className="flex justify-center">
<nav className="flex" role="navigation" aria-label="Navigation">
<div className="mr-2">
<span className="inline-flex items-center justify-center rounded leading-5 px-2.5 py-2 bg-white border border-slate-200 text-slate-300">
<span className="sr-only">Previous</span><wbr />
<svg className="h-4 w-4 fill-current" viewBox="0 0 16 16">
<path d="M9.4 13.4l1.4-1.4-4-4 4-4-1.4-1.4L4 8z" />
</svg>
</span>
</div>
<ul className="inline-flex text-sm font-medium -space-x-px shadow-sm">
<li>
<span className="inline-flex items-center justify-center rounded-l leading-5 px-3.5 py-2 bg-white border border-slate-200 text-indigo-500">1</span>
</li>
<li>
<a className="inline-flex items-center justify-center leading-5 px-3.5 py-2 bg-white hover:bg-indigo-500 border border-slate-200 text-slate-600 hover:text-white" href="#0">2</a>
</li>
<li>
<a className="inline-flex items-center justify-center leading-5 px-3.5 py-2 bg-white hover:bg-indigo-500 border border-slate-200 text-slate-600 hover:text-white" href="#0">3</a>
</li>
<li>
<span className="inline-flex items-center justify-center leading-5 px-3.5 py-2 bg-white border border-slate-200 text-slate-400"></span>
</li>
<li>
<a className="inline-flex items-center justify-center rounded-r leading-5 px-3.5 py-2 bg-white hover:bg-indigo-500 border border-slate-200 text-slate-600 hover:text-white" href="#0">9</a>
</li>
</ul>
<div className="ml-2">
<a href="#0" className="inline-flex items-center justify-center rounded leading-5 px-2.5 py-2 bg-white hover:bg-indigo-500 border border-slate-200 text-slate-600 hover:text-white shadow-sm">
<span className="sr-only">Next</span><wbr />
<svg className="h-4 w-4 fill-current" viewBox="0 0 16 16">
<path d="M6.6 13.4L5.2 12l4-4-4-4 1.4-1.4L12 8z" />
</svg>
</a>
</div>
</nav>
</div>
);
}
export default PaginationNumeric;

View File

@@ -1,37 +0,0 @@
import React from 'react';
function PaginationNumeric2() {
return (
<div>
<nav className="flex justify-between" role="navigation" aria-label="Navigation">
<div className="flex-1 mr-2">
<a className="btn bg-white border-slate-200 text-slate-300 cursor-not-allowed" href="#0" disabled>&lt;-<span className="hidden sm:inline">&nbsp;Previous</span></a>
</div>
<div className="grow text-center">
<ul className="inline-flex text-sm font-medium -space-x-px">
<li>
<span className="inline-flex items-center justify-center rounded-full leading-5 px-2 py-2 bg-white border border-slate-200 text-indigo-500 shadow-sm"><span className="w-5">1</span></span>
</li>
<li>
<a className="inline-flex items-center justify-center leading-5 px-2 py-2 text-slate-600 hover:text-indigo-500 border border-transparent" href="#0"><span className="w-5">2</span></a>
</li>
<li>
<a className="inline-flex items-center justify-center leading-5 px-2 py-2 text-slate-600 hover:text-indigo-500 border border-transparent" href="#0"><span className="w-5">3</span></a>
</li>
<li>
<span className="inline-flex items-center justify-center leading-5 px-2 py-2 text-slate-400"></span>
</li>
<li>
<a className="inline-flex items-center justify-center rounded-r leading-5 px-2 py-2 text-slate-600 hover:text-indigo-500 border border-transparent" href="#0"><span className="w-5">9</span></a>
</li>
</ul>
</div>
<div className="flex-1 text-right ml-2">
<a className="btn bg-white border-slate-200 hover:border-slate-300 text-indigo-500" href="#0"><span className="hidden sm:inline">Next&nbsp;</span>-&gt;</a>
</div>
</nav>
</div>
);
}
export default PaginationNumeric2;

View File

@@ -1,79 +0,0 @@
import React from 'react';
function Toast({
children,
className,
type,
open,
setOpen
}) {
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-500';
case 'error':
return 'bg-rose-500';
case 'success':
return 'bg-emerald-500';
default:
return 'bg-indigo-500';
}
};
return (
<>
{open &&
<div className={className}>
<div className={`inline-flex min-w-80 px-4 py-2 rounded-sm text-sm text-white ${typeColor(type)}`}>
<div className="flex w-full justify-between items-start">
<div className="flex">
{typeIcon(type)}
<div className="font-medium">
{children}
</div>
</div>
<button className="opacity-70 hover:opacity-80 ml-3 mt-[3px]" onClick={() => setOpen(false)}>
<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>
}
</>
);
}
export default Toast;

View File

@@ -1,36 +1,43 @@
import React from 'react';
function Toast2({
children,
className,
type,
open,
setOpen
}) {
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">
<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">
<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">
<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">
<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>
);
@@ -50,30 +57,34 @@ function Toast2({
}
};
return (
<>
{open &&
<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={() => setOpen(false)}>
<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>
}
</>
);
}
useEffect(() => {
const timerId = setTimeout(() => store.removeNotification(id), 3000);
return () => clearTimeout(timerId);
}, []);
export default Toast2;
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>
);
});

View File

@@ -1,66 +0,0 @@
import React from 'react';
function Toast3({
children,
className,
type,
open,
setOpen
}) {
const typeIcon = (type) => {
switch (type) {
case 'warning':
return (
<svg className="w-4 h-4 shrink-0 fill-current text-amber-500 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 text-rose-500 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 text-emerald-500 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 text-indigo-500 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>
);
}
};
return (
<>
{open &&
<div className={className}>
<div className="inline-flex min-w-80 px-4 py-2 rounded-sm text-sm bg-white shadow-lg border border-slate-200 text-slate-600">
<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={() => setOpen(false)}>
<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>
}
</>
);
}
export default Toast3;

View File

@@ -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;

View File

@@ -4,7 +4,7 @@
// Customise flatpickr
$calendarPadding: 24px;
$daySize: 36px;
$daysWidth: $daySize*7;
$daysWidth: $daySize * 7;
@keyframes fpFadeInDown {
from {
@@ -18,63 +18,63 @@ $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,
.flatpickr-day.prevMonthDay,
.flatpickr-day,
.flatpickr-day.prevMonthDay,
.flatpickr-day.nextMonthDay,
.flatpickr-day.selected.startRange,
.flatpickr-day.startRange.startRange,
@@ -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;
}

View File

@@ -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;
}
&::-moz-focus-outer {
border: 0;
}
}
&::-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;
}
}

View File

@@ -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;
}

View File

@@ -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"] {
&:checked {
&:disabled {
+ label {
@apply cursor-not-allowed bg-slate-100 border border-slate-200;
+ 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;
}
}
}
}
}
}

View File

@@ -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 */
}

View File

@@ -3,11 +3,10 @@
@tailwind base;
@tailwind components;
// Additional styles
@import 'additional-styles/utility-patterns.scss';
@import 'additional-styles/range-slider.scss';
@import 'additional-styles/toggle-switch.scss';
@import 'additional-styles/flatpickr.scss';
@import 'additional-styles/theme.scss';
@tailwind utilities;
@tailwind utilities;

View File

@@ -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

Binary file not shown.

After

Width:  |  Height:  |  Size: 912 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 623 B

BIN
src/images/vpn_service.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

View File

@@ -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')
)
);

View File

@@ -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;

View File

@@ -1,461 +0,0 @@
import React, { useState, useEffect } from 'react';
import Sidebar from '../partials/Sidebar';
import Header from '../partials/Header';
function Calendar() {
const today = new Date();
const monthNames = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December']
const dayNames = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday']
const [sidebarOpen, setSidebarOpen] = useState(false);
const [month, setMonth] = useState(today.getMonth());
// eslint-disable-next-line no-unused-vars
const [year, setYear] = useState(today.getFullYear());
const [daysInMonth, setDaysInMonth] = useState([])
const [startingBlankDays, setStartingBlankDays] = useState([])
const [endingBlankDays, setEndingBlankDays] = useState([])
const events = [
// Previous month
{
eventStart: new Date(new Date().getFullYear(), new Date().getMonth() - 1, 8, 3),
eventEnd: new Date(new Date().getFullYear(), new Date().getMonth() - 1, 8, 7),
eventName: '⛱️ Relax for 2 at Marienbad',
eventColor: 'indigo'
},
{
eventStart: new Date(new Date().getFullYear(), new Date().getMonth() - 1, 12, 10),
eventEnd: new Date(new Date().getFullYear(), new Date().getMonth(), 12, 11),
eventName: 'Team Catch-up',
eventColor: 'sky'
},
{
eventStart: new Date(new Date().getFullYear(), new Date().getMonth() - 1, 18, 2),
eventEnd: '',
eventName: '✍️ New Project (2)',
eventColor: 'yellow'
},
// Current month
{
eventStart: new Date(new Date().getFullYear(), new Date().getMonth(), 1, 10),
eventEnd: new Date(new Date().getFullYear(), new Date().getMonth(), 1, 11),
eventName: 'Meeting w/ Patrick Lin',
eventColor: 'sky'
},
{
eventStart: new Date(new Date().getFullYear(), new Date().getMonth(), 1, 19),
eventEnd: '',
eventName: 'Reservation at La Ginestre',
eventColor: 'indigo'
},
{
eventStart: new Date(new Date().getFullYear(), new Date().getMonth(), 3, 9),
eventEnd: new Date(new Date().getFullYear(), new Date().getMonth(), 3, 10),
eventName: '✍️ New Project',
eventColor: 'yellow'
},
{
eventStart: new Date(new Date().getFullYear(), new Date().getMonth(), 7, 21),
eventEnd: new Date(new Date().getFullYear(), new Date().getMonth(), 7, 22),
eventName: '⚽ 2021 - Semi-final',
eventColor: 'red'
},
{
eventStart: new Date(new Date().getFullYear(), new Date().getMonth(), 9, 10),
eventEnd: new Date(new Date().getFullYear(), new Date().getMonth(), 9, 11),
eventName: 'Meeting w/Carolyn',
eventColor: 'sky'
},
{
eventStart: new Date(new Date().getFullYear(), new Date().getMonth(), 9, 13),
eventEnd: '',
eventName: 'Pick up Marta at school',
eventColor: 'emerald'
},
{
eventStart: new Date(new Date().getFullYear(), new Date().getMonth(), 9, 14),
eventEnd: new Date(new Date().getFullYear(), new Date().getMonth(), 9, 15),
eventName: 'Meeting w/ Patrick Lin',
eventColor: 'emerald'
},
{
eventStart: new Date(new Date().getFullYear(), new Date().getMonth(), 9, 19),
eventEnd: '',
eventName: 'Reservation at La Ginestre',
eventColor: 'indigo'
},
{
eventStart: new Date(new Date().getFullYear(), new Date().getMonth(), 11, 10),
eventEnd: new Date(new Date().getFullYear(), new Date().getMonth(), 11, 11),
eventName: '⛱️ Relax for 2 at Marienbad',
eventColor: 'indigo'
},
{
eventStart: new Date(new Date().getFullYear(), new Date().getMonth(), 11, 19),
eventEnd: '',
eventName: '⚽ 2021 - Semi-final',
eventColor: 'red'
},
{
eventStart: new Date(new Date().getFullYear(), new Date().getMonth(), 14, 10),
eventEnd: new Date(new Date().getFullYear(), new Date().getMonth(), 14, 11),
eventName: 'Team Catch-up',
eventColor: 'sky'
},
{
eventStart: new Date(new Date().getFullYear(), new Date().getMonth(), 21, 2),
eventEnd: '',
eventName: 'Pick up Marta at school',
eventColor: 'emerald'
},
{
eventStart: new Date(new Date().getFullYear(), new Date().getMonth(), 21, 3),
eventEnd: new Date(new Date().getFullYear(), new Date().getMonth(), 21, 7),
eventName: '✍️ New Project (2)',
eventColor: 'yellow'
},
{
eventStart: new Date(new Date().getFullYear(), new Date().getMonth(), 22, 10),
eventEnd: new Date(new Date().getFullYear(), new Date().getMonth(), 22, 11),
eventName: 'Team Catch-up',
eventColor: 'sky'
},
{
eventStart: new Date(new Date().getFullYear(), new Date().getMonth(), 22, 19),
eventEnd: '',
eventName: '⚽ 2021 - Semi-final',
eventColor: 'red'
},
{
eventStart: new Date(new Date().getFullYear(), new Date().getMonth(), 23, 0),
eventEnd: new Date(new Date().getFullYear(), new Date().getMonth(), 23, 23),
eventName: 'You stay at Meridiana B&B',
eventColor: 'indigo'
},
{
eventStart: new Date(new Date().getFullYear(), new Date().getMonth(), 25, 10),
eventEnd: new Date(new Date().getFullYear(), new Date().getMonth(), 25, 11),
eventName: 'Meeting w/ Kylie Joh',
eventColor: 'sky'
},
{
eventStart: new Date(new Date().getFullYear(), new Date().getMonth(), 29, 10),
eventEnd: new Date(new Date().getFullYear(), new Date().getMonth(), 29, 11),
eventName: 'Call Request ->',
eventColor: 'sky'
},
// Next month
{
eventStart: new Date(new Date().getFullYear(), new Date().getMonth() + 1, 2, 3),
eventEnd: new Date(new Date().getFullYear(), new Date().getMonth() + 1, 2, 7),
eventName: '✍️ New Project (2)',
eventColor: 'yellow'
},
{
eventStart: new Date(new Date().getFullYear(), new Date().getMonth() + 1, 14, 10),
eventEnd: new Date(new Date().getFullYear(), new Date().getMonth(), 14, 11),
eventName: 'Team Catch-up',
eventColor: 'sky'
},
{
eventStart: new Date(new Date().getFullYear(), new Date().getMonth() + 1, 25, 2),
eventEnd: new Date(new Date().getFullYear(), new Date().getMonth() + 1, 25, 3),
eventName: 'Pick up Marta at school',
eventColor: 'emerald'
},
{
eventStart: new Date(new Date().getFullYear(), new Date().getMonth() + 1, 27, 21),
eventEnd: new Date(new Date().getFullYear(), new Date().getMonth() + 1, 27, 22),
eventName: '⚽ 2021 - Semi-final',
eventColor: 'red'
},
];
const isToday = (date) => {
const day = new Date(year, month, date);
return today.toDateString() === day.toDateString() ? true : false;
}
const getEvents = (date) => {
return events.filter(e => new Date(e.eventStart).toDateString() === new Date(year, month, date).toDateString());
}
const eventColor = (color) => {
switch (color) {
case 'sky':
return 'text-white bg-sky-500';
case 'indigo':
return 'text-white bg-indigo-500';
case 'yellow':
return 'text-white bg-amber-500';
case 'emerald':
return 'text-white bg-emerald-500';
case 'red':
return 'text-white bg-rose-400';
default:
return '';
}
};
const getDays = () => {
const days = new Date(year, month + 1, 0).getDate();
// starting empty cells (previous month)
const startingDayOfWeek = new Date(year, month).getDay();
let startingBlankDaysArray = [];
for (let i = 1; i <= startingDayOfWeek; i++) {
startingBlankDaysArray.push(i);
}
// ending empty cells (next month)
const endingDayOfWeek = new Date(year, month + 1, 0).getDay();
let endingBlankDaysArray = [];
for (let i = 1; i < 7 - endingDayOfWeek; i++) {
endingBlankDaysArray.push(i);
}
// current month cells
let daysArray = [];
for (let i = 1; i <= days; i++) {
daysArray.push(i);
}
setStartingBlankDays(startingBlankDaysArray);
setEndingBlankDays(endingBlankDaysArray);
setDaysInMonth(daysArray);
}
useEffect(() => {
getDays();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
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-4">
{/* Left: Title */}
<div className="mb-4 sm:mb-0">
<h1 className="text-2xl md:text-3xl text-slate-800 font-bold"><span>{`${monthNames[month]} ${year}`}</span> </h1>
</div>
{/* Right: Actions */}
<div className="grid grid-flow-col sm:auto-cols-max justify-start sm:justify-end gap-2">
{/* Previous month button */}
<button
className="btn px-2.5 bg-white border-slate-200 hover:border-slate-300 text-slate-500 hover:text-slate-600 disabled:border-slate-200 disabled:bg-slate-100 disabled:text-slate-400 disabled:cursor-not-allowed"
disabled={month === 0 ? true : false}
onClick={() => {setMonth(month - 1);getDays();}}
>
<span className="sr-only">Previous month</span><wbr />
<svg className="h-4 w-4 fill-current" viewBox="0 0 16 16">
<path d="M9.4 13.4l1.4-1.4-4-4 4-4-1.4-1.4L4 8z" />
</svg>
</button>
{/* Next month button */}
<button
className="btn px-2.5 bg-white border-slate-200 hover:border-slate-300 text-slate-500 hover:text-slate-600 disabled:border-slate-200 disabled:bg-slate-100 disabled:text-slate-400 disabled:cursor-not-allowed"
disabled={month === 11 ? true : false}
onClick={() => {setMonth(month + 1);getDays();}}
>
<span className="sr-only">Next month</span><wbr />
<svg className="h-4 w-4 fill-current" viewBox="0 0 16 16">
<path d="M6.6 13.4L5.2 12l4-4-4-4 1.4-1.4L12 8z" />
</svg>
</button>
<hr className="w-px h-full bg-slate-200 mx-1" />
{/* Create event 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">Create Event</span>
</button>
</div>
</div>
{/* Filters and view buttons */}
<div className="sm:flex sm:justify-between sm:items-center mb-4">
{/* Filters */}
<div className="mb-4 sm:mb-0 mr-2">
<ul className="flex flex-wrap items-center -m-1">
<li className="m-1">
<button className="btn-sm bg-white border-slate-200 hover:border-slate-300 text-slate-500">
<div className="w-1 h-3.5 bg-sky-500 shrink-0"></div>
<span className="ml-1.5">Acme Inc.</span>
</button>
</li>
<li className="m-1">
<button className="btn-sm bg-white border-slate-200 hover:border-slate-300 text-slate-500">
<div className="w-1 h-3.5 bg-emerald-500 shrink-0"></div>
<span className="ml-1.5">Life & Family</span>
</button>
</li>
<li className="m-1">
<button className="btn-sm bg-white border-slate-200 hover:border-slate-300 text-slate-500">
<div className="w-1 h-3.5 bg-indigo-500 shrink-0"></div>
<span className="ml-1.5">Reservations</span>
</button>
</li>
<li className="m-1">
<button className="btn-sm bg-white border-slate-200 hover:border-slate-300 text-slate-500">
<div className="w-1 h-3.5 bg-rose-400 shrink-0"></div>
<span className="ml-1.5">Events</span>
</button>
</li>
<li className="m-1">
<button className="btn-sm bg-white border-slate-200 hover:border-slate-300 text-slate-500">
<div className="w-1 h-3.5 bg-amber-500 shrink-0"></div>
<span className="ml-1.5">Misc</span>
</button>
</li>
<li className="m-1">
<button className="btn-sm bg-white border-slate-200 hover:border-slate-300 text-indigo-500">+Add New</button>
</li>
</ul>
</div>
{/* View buttons (requires custom integration) */}
<div className="flex flex-nowrap -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">Month</button>
<button className="btn bg-white border-slate-200 hover:bg-slate-50 text-slate-600 rounded-none first:rounded-l last:rounded-r">Week</button>
<button className="btn bg-white border-slate-200 hover:bg-slate-50 text-slate-600 rounded-none first:rounded-l last:rounded-r">Day</button>
</div>
</div>
{/* Calendar table */}
<div className="bg-white rounded-sm shadow overflow-hidden">
{/* Days of the week */}
<div className="grid grid-cols-7 gap-px border-b border-slate-200">
{
dayNames.map(day => {
return (
<div className="px-1 py-3" key={day}>
<div className="text-slate-500 text-sm font-medium text-center lg:hidden">{day.substring(0,3)}</div>
<div className="text-slate-500 text-sm font-medium text-center hidden lg:block">{day}</div>
</div>
)
})
}
</div>
{/* Day cells */}
<div className="grid grid-cols-7 gap-px bg-slate-200">
{/* Diagonal stripes pattern */}
<svg className="sr-only">
<defs>
<pattern id="stripes" patternUnits="userSpaceOnUse" width="5" height="5" patternTransform="rotate(135)">
<line className="stroke-current text-slate-200 opacity-50" x1="0" y="0" x2="0" y2="5" strokeWidth="2" />
</pattern>
</defs>
</svg>
{/* Empty cells (previous month) */}
{
startingBlankDays.map(blankday => {
return (
<div className="bg-slate-50 h-20 sm:h-28 lg:h-36" key={blankday}>
<svg xmlns="http://www.w3.org/2000/svg" width="100%" height="100%">
<rect width="100%" height="100%" fill="url(#stripes)" />
</svg>
</div>
)
})
}
{/* Days of the current month */}
{
daysInMonth.map(day => {
return (
<div className="relative bg-white h-20 sm:h-28 lg:h-36 overflow-hidden" key={day}>
<div className="h-full flex flex-col justify-between">
{/* Events */}
<div className="grow flex flex-col relative p-0.5 sm:p-1.5 overflow-hidden">
{
getEvents(day).map(event => {
return (
<button className="relative w-full text-left mb-1" key={event.eventName}>
<div className={`px-2 py-0.5 rounded overflow-hidden ${eventColor(event.eventColor)}`}>
{/* Event name */}
<div className="text-xs font-semibold truncate">{event.eventName}</div>
{/* Event time */}
<div className="text-xs uppercase truncate hidden sm:block">
{/* Start date */}
{event.eventStart &&
<span>{event.eventStart.toLocaleTimeString([], {hour12: true, hour: 'numeric', minute:'numeric'})}</span>
}
{/* End date */}
{event.eventEnd &&
<span>
- <span>{event.eventEnd.toLocaleTimeString([], {hour12: true, hour: 'numeric', minute:'numeric'})}</span>
</span>
}
</div>
</div>
</button>
)
})
}
<div className="absolute bottom-0 left-0 right-0 h-4 bg-gradient-to-t from-white to-transparent pointer-events-none" aria-hidden="true"></div>
</div>
{/* Cell footer */}
<div className="flex justify-between items-center p-0.5 sm:p-1.5">
{/* More button (if more than 2 events) */}
{getEvents(day).length > 2 &&
<button className="text-xs text-slate-500 font-medium whitespace-nowrap text-center sm:py-0.5 px-0.5 sm:px-2 border border-slate-200 rounded">
<span className="md:hidden">+</span><span>{getEvents(day).length - 2}</span> <span className="hidden md:inline">more</span>
</button>
}
{/* Day number */}
<button className={`inline-flex ml-auto w-6 h-6 items-center justify-center text-xs sm:text-sm font-medium text-center rounded-full hover:bg-indigo-100 ${isToday(day) && 'text-indigo-500'}`}>{day}</button>
</div>
</div>
</div>
)
})
}
{/* Empty cells (next month) */}
{
endingBlankDays.map(blankday => {
return (
<div className="bg-slate-50 h-20 sm:h-28 lg:h-36" key={blankday}>
<svg xmlns="http://www.w3.org/2000/svg" width="100%" height="100%">
<rect width="100%" height="100%" fill="url(#stripes)" />
</svg>
</div>
)
})
}
</div>
</div>
</div>
</main>
</div>
</div>
);
}
export default Calendar;

View File

@@ -1,423 +0,0 @@
import React, { useState } from 'react';
import Sidebar from '../partials/Sidebar';
import Header from '../partials/Header';
import SearchForm from '../partials/actions/SearchForm';
import FilterButton from '../components/DropdownFilter';
import CampaignsCard from '../partials/campaigns/CampaignsCard';
import PaginationNumeric from '../components/PaginationNumeric';
import Image01 from '../images/user-28-01.jpg';
import Image02 from '../images/user-28-02.jpg';
import Image03 from '../images/user-28-03.jpg';
import Image04 from '../images/user-28-04.jpg';
import Image05 from '../images/user-28-05.jpg';
import Image06 from '../images/user-28-06.jpg';
import Image07 from '../images/user-28-07.jpg';
import Image08 from '../images/user-28-08.jpg';
import Image09 from '../images/user-28-09.jpg';
import Image10 from '../images/user-28-10.jpg';
import Image11 from '../images/user-28-11.jpg';
import Image12 from '../images/user-28-12.jpg';
function Campaigns() {
const items = [
{
id: 0,
category: '1',
members: [
{
name: 'User 01',
image: Image01,
link: '#0'
},
{
name: 'User 02',
image: Image02,
link: '#0'
},
{
name: 'User 03',
image: Image03,
link: '#0'
},
],
title: 'Monitor progress in Real Time Value',
link: '#0',
content: 'Lorem ipsum is placeholder text commonly used in the graphic, print, and publishing industries for previewing layouts.',
dates: {
from: 'Jan 20',
to: 'Jan 27'
},
type: 'One-Time'
},
{
id: 1,
category: '2',
members: [
{
name: 'User 04',
image: Image04,
link: '#0'
},
{
name: 'User 05',
image: Image05,
link: '#0'
},
],
title: 'Monitor progress in Real Time Value',
link: '#0',
content: 'Lorem ipsum is placeholder text commonly used in the graphic, print, and publishing industries for previewing layouts.',
dates: {
from: 'Jan 20',
to: 'Jan 27'
},
type: 'Off-Track'
},
{
id: 3,
category: '3',
members: [
{
name: 'User 07',
image: Image07,
link: '#0'
},
{
name: 'User 08',
image: Image08,
link: '#0'
},
{
name: 'User 09',
image: Image09,
link: '#0'
},
],
title: 'Monitor progress in Real Time Value',
link: '#0',
content: 'Lorem ipsum is placeholder text commonly used in the graphic, print, and publishing industries for previewing layouts.',
dates: {
from: 'Jan 20',
to: 'Jan 27'
},
type: 'At Risk'
},
{
id: 4,
category: '1',
members: [
{
name: 'User 10',
image: Image10,
link: '#0'
},
],
title: 'Monitor progress in Real Time Value',
link: '#0',
content: 'Lorem ipsum is placeholder text commonly used in the graphic, print, and publishing industries for previewing layouts.',
dates: {
from: 'Jan 20',
to: 'Jan 27'
},
type: 'At Risk'
},
{
id: 5,
category: '4',
members: [
{
name: 'User 11',
image: Image11,
link: '#0'
},
{
name: 'User 05',
image: Image05,
link: '#0'
},
{
name: 'User 12',
image: Image12,
link: '#0'
},
],
title: 'Monitor progress in Real Time Value',
link: '#0',
content: 'Lorem ipsum is placeholder text commonly used in the graphic, print, and publishing industries for previewing layouts.',
dates: {
from: 'Jan 20',
to: 'Jan 27'
},
type: 'One-Time'
},
{
id: 6,
category: '2',
members: [
{
name: 'User 07',
image: Image07,
link: '#0'
},
{
name: 'User 04',
image: Image04,
link: '#0'
},
{
name: 'User 11',
image: Image11,
link: '#0'
},
],
title: 'Monitor progress in Real Time Value',
link: '#0',
content: 'Lorem ipsum is placeholder text commonly used in the graphic, print, and publishing industries for previewing layouts.',
dates: {
from: 'Jan 20',
to: 'Jan 27'
},
type: 'At Risk'
},
{
id: 7,
category: '4',
members: [
{
name: 'User 01',
image: Image01,
link: '#0'
},
{
name: 'User 02',
image: Image02,
link: '#0'
},
{
name: 'User 06',
image: Image06,
link: '#0'
},
],
title: 'Monitor progress in Real Time Value',
link: '#0',
content: 'Lorem ipsum is placeholder text commonly used in the graphic, print, and publishing industries for previewing layouts.',
dates: {
from: 'Jan 20',
to: 'Jan 27'
},
type: 'One-Time'
},
{
id: 8,
category: '1',
members: [
{
name: 'User 09',
image: Image09,
link: '#0'
},
{
name: 'User 01',
image: Image01,
link: '#0'
},
],
title: 'Monitor progress in Real Time Value',
link: '#0',
content: 'Lorem ipsum is placeholder text commonly used in the graphic, print, and publishing industries for previewing layouts.',
dates: {
from: 'Jan 20',
to: 'Jan 27'
},
type: 'Off-Track'
},
{
id: 9,
category: '3',
members: [
{
name: 'User 07',
image: Image07,
link: '#0'
},
{
name: 'User 08',
image: Image08,
link: '#0'
},
{
name: 'User 09',
image: Image09,
link: '#0'
},
{
name: 'User 06',
image: Image06,
link: '#0'
},
],
title: 'Monitor progress in Real Time Value',
link: '#0',
content: 'Lorem ipsum is placeholder text commonly used in the graphic, print, and publishing industries for previewing layouts.',
dates: {
from: 'Jan 20',
to: 'Jan 27'
},
type: 'One-Time'
},
{
id: 10,
category: '4',
members: [
{
name: 'User 06',
image: Image06,
link: '#0'
},
{
name: 'User 11',
image: Image11,
link: '#0'
},
],
title: 'Monitor progress in Real Time Value',
link: '#0',
content: 'Lorem ipsum is placeholder text commonly used in the graphic, print, and publishing industries for previewing layouts.',
dates: {
from: 'Jan 20',
to: 'Jan 27'
},
type: 'Off-Track'
},
{
id: 11,
category: '2',
members: [
{
name: 'User 05',
image: Image05,
link: '#0'
},
],
title: 'Monitor progress in Real Time Value',
link: '#0',
content: 'Lorem ipsum is placeholder text commonly used in the graphic, print, and publishing industries for previewing layouts.',
dates: {
from: 'Jan 20',
to: 'Jan 27'
},
type: 'Off-Track'
},
{
id: 12,
category: '3',
members: [
{
name: 'User 07',
image: Image07,
link: '#0'
},
{
name: 'User 08',
image: Image08,
link: '#0'
},
{
name: 'User 09',
image: Image09,
link: '#0'
},
],
title: 'Monitor progress in Real Time Value',
link: '#0',
content: 'Lorem ipsum is placeholder text commonly used in the graphic, print, and publishing industries for previewing layouts.',
dates: {
from: 'Jan 20',
to: 'Jan 27'
},
type: 'At Risk'
},
];
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">Campaigns </h1>
</div>
{/* Right: Actions */}
<div className="grid grid-flow-col sm:auto-cols-max justify-start sm:justify-end gap-2">
{/* Search form */}
<SearchForm />
{/* Filter button */}
<FilterButton align="right" />
{/* Create campaign 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">Create Campaign</span>
</button>
</div>
</div>
{/* Cards */}
<div className="grid grid-cols-12 gap-6">
{
items.map(item => {
return (
<CampaignsCard
key={item.id}
id={item.id}
category={item.category}
members={item.members}
title={item.title}
link={item.link}
content={item.content}
dates={item.dates}
type={item.type}
/>
)
})
}
</div>
{/* Pagination */}
<div className="mt-8">
<PaginationNumeric />
</div>
</div>
</main>
</div>
</div>
);
}
export default Campaigns;

Some files were not shown because too many files have changed in this diff Show More