From f1b2f3f13b0099803bdfb785c02acd90ef73beb3 Mon Sep 17 00:00:00 2001 From: Behnam Jaberi Date: Thu, 22 Jun 2023 18:27:44 +0330 Subject: [PATCH 01/10] Add wagmi component auth to projcet --- src/assets/images/tokens/arbitrum.svg | 9 ++ src/assets/images/tokens/celo.svg | 11 +++ src/assets/images/tokens/eth.png | Bin 0 -> 3954 bytes src/assets/images/tokens/polygon.svg | 16 ++++ src/components/AppHeader.js | 29 +++++- .../header/auth/AuthHeaderDropDown.js | 83 ++++++++++++++++++ src/components/header/auth/index.js | 3 + src/scss/_custom.scss | 7 ++ 8 files changed, 154 insertions(+), 4 deletions(-) create mode 100644 src/assets/images/tokens/arbitrum.svg create mode 100644 src/assets/images/tokens/celo.svg create mode 100644 src/assets/images/tokens/eth.png create mode 100644 src/assets/images/tokens/polygon.svg create mode 100644 src/components/header/auth/AuthHeaderDropDown.js create mode 100644 src/components/header/auth/index.js diff --git a/src/assets/images/tokens/arbitrum.svg b/src/assets/images/tokens/arbitrum.svg new file mode 100644 index 000000000..d439bc6f6 --- /dev/null +++ b/src/assets/images/tokens/arbitrum.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/src/assets/images/tokens/celo.svg b/src/assets/images/tokens/celo.svg new file mode 100644 index 000000000..bd24e97d7 --- /dev/null +++ b/src/assets/images/tokens/celo.svg @@ -0,0 +1,11 @@ + + + + + + + diff --git a/src/assets/images/tokens/eth.png b/src/assets/images/tokens/eth.png new file mode 100644 index 0000000000000000000000000000000000000000..760946e76911accfd17cc84d84896c2ffab3b752 GIT binary patch literal 3954 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 M07*qoM6N<$f?!r`Q2+n{ literal 0 HcmV?d00001 diff --git a/src/assets/images/tokens/polygon.svg b/src/assets/images/tokens/polygon.svg new file mode 100644 index 000000000..a5bb6124f --- /dev/null +++ b/src/assets/images/tokens/polygon.svg @@ -0,0 +1,16 @@ + + + + + + + + diff --git a/src/components/AppHeader.js b/src/components/AppHeader.js index dd5f544e3..3d26dabb3 100644 --- a/src/components/AppHeader.js +++ b/src/components/AppHeader.js @@ -15,11 +15,28 @@ import CIcon from '@coreui/icons-react' import { cilBell, cilEnvelopeOpen, cilList, cilMenu } from '@coreui/icons' import { AppBreadcrumb } from './index' -import { AppHeaderDropdown } from './header/index' +import { AuthHeaderDropdown } from './header/auth/index' import { logo } from 'src/assets/brand/logo' +// Wagnumi Auth // +import { EthereumClient, w3mConnectors, w3mProvider } from '@web3modal/ethereum' +import { Web3Modal } from '@web3modal/react' +import { configureChains, createConfig, WagmiConfig } from 'wagmi' +import { arbitrum, mainnet, polygon } from 'wagmi/chains' + +const chains = [arbitrum, mainnet, polygon] +const projectId = 'YOUR_PROJECT_ID' + +const { publicClient } = configureChains(chains, [w3mProvider({ projectId })]) +const wagmiConfig = createConfig({ + autoConnect: true, + connectors: w3mConnectors({ projectId, version: 1, chains }), + publicClient +}) + const AppHeader = () => { const dispatch = useDispatch() + const ethereumClient = new EthereumClient(wagmiConfig, chains) const sidebarShow = useSelector((state) => state.sidebarShow) return ( @@ -47,6 +64,13 @@ const AppHeader = () => { Settings + + + + + + + @@ -64,9 +88,6 @@ const AppHeader = () => { - - - diff --git a/src/components/header/auth/AuthHeaderDropDown.js b/src/components/header/auth/AuthHeaderDropDown.js new file mode 100644 index 000000000..c27e31fb1 --- /dev/null +++ b/src/components/header/auth/AuthHeaderDropDown.js @@ -0,0 +1,83 @@ +import React from "react"; +import { useWeb3Modal } from '@web3modal/react' +import { useNetwork, useSwitchNetwork, useAccount } from 'wagmi' + +import { + CAvatar, + CBadge, + CButton, + CDropdown, + CDropdownMenu, + CDropdownItem, + CDropdownToggle +} from '@coreui/react' +import ethIcon from '../../../assets/images/tokens/eth.png' +import arbitIcon from '../../../assets/images/tokens/arbitrum.svg' +import maticIcon from '../../../assets/images/tokens/polygon.svg' + + + +const ConnectWalletButton = () => { + const { chain } = useNetwork() + const { open } = useWeb3Modal() + const { chains, isLoading, pendingChainId, switchNetwork } = useSwitchNetwork() + const { address, status } = useAccount() + const supportedNetwork = [ + { + "name": "Ethereum", + "cover": ethIcon + }, + { + "name": "Arbitrum One", + "cover": arbitIcon + }, { + "name": "Polygon", + "cover": maticIcon + } + ] + + const findToken = (name) => { + return supportedNetwork.find(x => x.name === name) + } + + return ( + <> +
+ open()} color="secondary" variant="outline" + className={address ? 'w-50 text-truncate h-75' : 'w-auto'}> + {address ? address : 'Connect Your Wallet'} + + {chain && + + + {findToken(chain.name) ? '' : 'Unsupported Network Choosen'} + + {findToken(chain.name) && + New alerts + } + + + {chains.map((x) => ( switchNetwork?.(x.id)} + > + + {x.name} + {isLoading && pendingChainId === x.id && ' (switching)'} + ) + )} + + } +
+ + ) +}; + +export default ConnectWalletButton; \ No newline at end of file diff --git a/src/components/header/auth/index.js b/src/components/header/auth/index.js new file mode 100644 index 000000000..fc48eaf49 --- /dev/null +++ b/src/components/header/auth/index.js @@ -0,0 +1,3 @@ +import AuthHeaderDropdown from './AuthHeaderDropDown' + +export { AuthHeaderDropdown } diff --git a/src/scss/_custom.scss b/src/scss/_custom.scss index 15d367af4..c53e63d02 100644 --- a/src/scss/_custom.scss +++ b/src/scss/_custom.scss @@ -1 +1,8 @@ // Here you can add other styles + + +// Size // +.w-15-icon { + width: 15px; + height: 15px; +} \ No newline at end of file From 5b7e96be6aeb66f2b149ee7e2e8542b211a64958 Mon Sep 17 00:00:00 2001 From: Behnam Jaberi Date: Fri, 28 Jul 2023 18:49:51 +0330 Subject: [PATCH 02/10] Add rainbow kit to project and configure that --- package.json | 55 +++++++++++++++++--------------- src/components/rainbow/button.js | 22 +++++++++++++ src/components/rainbow/index.js | 34 ++++++++++++++++++++ 3 files changed, 85 insertions(+), 26 deletions(-) create mode 100644 src/components/rainbow/button.js create mode 100644 src/components/rainbow/index.js diff --git a/package.json b/package.json index da08efaab..f54e6f2e9 100644 --- a/package.json +++ b/package.json @@ -22,38 +22,41 @@ "test:debug": "react-scripts --inspect-brk test --runInBand" }, "dependencies": { - "@coreui/chartjs": "^3.1.1", - "@coreui/coreui": "^4.2.6", - "@coreui/icons": "^3.0.1", - "@coreui/icons-react": "^2.1.0", - "@coreui/react": "^4.6.0", - "@coreui/react-chartjs": "^2.1.2", - "@coreui/utils": "^2.0.1", - "chart.js": "^3.9.1", - "classnames": "^2.3.2", - "core-js": "^3.29.0", - "prop-types": "^15.8.1", - "react": "^18.2.0", - "react-app-polyfill": "^3.0.0", - "react-dom": "^18.2.0", - "react-redux": "^8.0.5", - "react-router-dom": "^6.8.2", + "@coreui/chartjs": "3.1.2", + "@coreui/coreui": "4.2.6", + "@coreui/icons": "3.0.1", + "@coreui/icons-react": "2.1.0", + "@coreui/react": "4.9.0-rc.0", + "@coreui/react-chartjs": "2.1.3", + "@coreui/utils": "2.0.2", + "@rainbow-me/rainbowkit": "1.0.7", + "chart.js": "3.9.1", + "classnames": "2.3.2", + "core-js": "3.31.0", + "prop-types": "15.8.1", + "react": "18.2.0", + "react-app-polyfill": "3.0.0", + "react-dom": "18.2.0", + "react-redux": "8.1.1", + "react-router-dom": "6.14.0", "redux": "4.2.1", - "simplebar-react": "^2.4.3" + "simplebar-react": "2.4.3", + "viem": "1.4.2", + "wagmi": "1.3.9" }, "devDependencies": { - "@testing-library/jest-dom": "^5.16.5", - "@testing-library/react": "^14.0.0", - "@testing-library/user-event": "^14.4.3", - "eslint-config-prettier": "^8.7.0", - "eslint-plugin-prettier": "^4.2.1", - "prettier": "2.8.4", + "@testing-library/jest-dom": "5.16.5", + "@testing-library/react": "14.0.0", + "@testing-library/user-event": "14.4.3", + "eslint-config-prettier": "8.8.0", + "eslint-plugin-prettier": "4.2.1", + "prettier": "2.8.8", "react-scripts": "5.0.1", - "sass": "^1.58.3", - "web-vitals": "^3.1.1" + "sass": "1.63.6", + "web-vitals": "3.3.2" }, "engines": { "node": ">=10", "npm": ">=6" } -} +} \ No newline at end of file diff --git a/src/components/rainbow/button.js b/src/components/rainbow/button.js new file mode 100644 index 000000000..adc25b21c --- /dev/null +++ b/src/components/rainbow/button.js @@ -0,0 +1,22 @@ +import React, { useEffect } from 'react' +import { darkTheme, RainbowKitProvider, ConnectButton } from '@rainbow-me/rainbowkit' +import { configureChains } from 'wagmi' +import { mainnet, polygon, optimism, arbitrum, zora } from 'wagmi/chains' +import { alchemyProvider } from 'wagmi/providers/alchemy' +import { publicProvider } from 'wagmi/providers/public' +import '@rainbow-me/rainbowkit/styles.css' + +const { chains } = configureChains( + [mainnet, polygon, optimism, arbitrum, zora], + [alchemyProvider({ apiKey: process.env.REACT_APP_ALCHEMY_ID }), publicProvider()], +) + +const RainBowButton = () => { + return ( + + + + ) +} + +export default RainBowButton diff --git a/src/components/rainbow/index.js b/src/components/rainbow/index.js new file mode 100644 index 000000000..983e4740b --- /dev/null +++ b/src/components/rainbow/index.js @@ -0,0 +1,34 @@ +// src/components/rainbow/index.js + +import React from 'react' +import { getDefaultWallets } from '@rainbow-me/rainbowkit' +import { configureChains, createConfig, WagmiConfig } from 'wagmi' +import { mainnet, polygon, optimism, arbitrum, zora } from 'wagmi/chains' +import { alchemyProvider } from 'wagmi/providers/alchemy' +import { publicProvider } from 'wagmi/providers/public' +import RainBowButton from './button' + +const { chains, publicClient } = configureChains( + [mainnet, polygon, optimism, arbitrum, zora], + [alchemyProvider({ apiKey: process.env.REACT_APP_ALCHEMY_ID }), publicProvider()], +) + +const { connectors } = getDefaultWallets({ + appName: 'Wallet Connect With RainBow', + projectId: process.env.REACT_APP_RAINBOW_KEY, + chains, +}) + +const wagmiConfig = createConfig({ + autoConnect: true, + connectors, + publicClient, +}) + +export const WalletButton = () => { + return ( + + + + ) +} From 65f006823445a097a3325012f2e9af52b57b1e21 Mon Sep 17 00:00:00 2001 From: Behnam Jaberi Date: Fri, 28 Jul 2023 20:20:00 +0330 Subject: [PATCH 03/10] Update gitignore and remove env file --- .env | 2 -- .env.example | 5 +++++ .gitignore | 1 + 3 files changed, 6 insertions(+), 2 deletions(-) delete mode 100644 .env create mode 100644 .env.example diff --git a/.env b/.env deleted file mode 100644 index 0c48d3cda..000000000 --- a/.env +++ /dev/null @@ -1,2 +0,0 @@ -PORT=3000 -CHOKIDAR_USEPOLLING=true diff --git a/.env.example b/.env.example new file mode 100644 index 000000000..9afbcbac8 --- /dev/null +++ b/.env.example @@ -0,0 +1,5 @@ +PORT=3000 +CHOKIDAR_USEPOLLING=true +REACT_APP_BASE_URL="" +REACT_APP_ALCHEMY_ID="" +REACT_APP_RAINBOW_KEY="" diff --git a/.gitignore b/.gitignore index e080cd5fb..8d595a915 100644 --- a/.gitignore +++ b/.gitignore @@ -19,6 +19,7 @@ yarn.lock .env.development.local .env.test.local .env.production.local +.env npm-debug.log* yarn-debug.log* From 32f1658abe380dc2099f89422b41fc4af99926f4 Mon Sep 17 00:00:00 2001 From: Behnam Jaberi Date: Fri, 28 Jul 2023 20:20:18 +0330 Subject: [PATCH 04/10] Add redux, saga --- src/redux/modules/init/index.js | 31 ++++++++++++++++++++ src/redux/modules/userNonce/index.js | 44 ++++++++++++++++++++++++++++ src/redux/modules/userSign/index.js | 28 ++++++++++++++++++ src/redux/reducer.js | 12 ++++++++ src/redux/sagas.js | 7 +++++ src/redux/store.js | 16 ++++++++++ 6 files changed, 138 insertions(+) create mode 100644 src/redux/modules/init/index.js create mode 100644 src/redux/modules/userNonce/index.js create mode 100644 src/redux/modules/userSign/index.js create mode 100644 src/redux/reducer.js create mode 100644 src/redux/sagas.js create mode 100644 src/redux/store.js diff --git a/src/redux/modules/init/index.js b/src/redux/modules/init/index.js new file mode 100644 index 000000000..e01581da4 --- /dev/null +++ b/src/redux/modules/init/index.js @@ -0,0 +1,31 @@ +import { createSlice } from '@reduxjs/toolkit' +import { useDispatch, useSelector } from 'react-redux' +import { useCallback } from 'react' + +const initialState = { + sidebarShow: true, +} + +const initSlice = createSlice({ + name: 'init', + initialState, + reducers: { + setSidebarShow: (state) => { + state.sidebarShow = !state.sidebarShow + }, + }, +}) + +export function useToggleSidebar() { + const dispatch = useDispatch() + const sidebarShow = useSelector((state) => state.init.sidebarShow) + + const toggleSidebar = useCallback(() => { + dispatch(initSlice.actions.setSidebarShow()) + }, [dispatch]) + + return { sidebarShow, toggleSidebar } +} + +export const { setSidebarShow } = initSlice.actions +export default initSlice.reducer diff --git a/src/redux/modules/userNonce/index.js b/src/redux/modules/userNonce/index.js new file mode 100644 index 000000000..d9da600cc --- /dev/null +++ b/src/redux/modules/userNonce/index.js @@ -0,0 +1,44 @@ +import { useCallback } from 'react' +import { put, takeEvery } from 'redux-saga/effects' +import ReduxFetchState from 'redux-fetch-state' +import { getAccount, signMessage } from '@wagmi/core' +import { useDispatch } from 'react-redux' +import apiPlugin from '../../../services/api' +import { userSignActions } from '../userSign' +const API_URL = process.env.REACT_APP_BASE_URL + +const { actions, actionTypes, reducer } = new ReduxFetchState('userNonce') + +export function* watchUserNonce(action) { + const { address } = action.payload + try { + const response = yield apiPlugin.getData(`${API_URL}/nonce/${address}`) + const { message } = response + const signature = yield signMessage({ message: message }) + yield put(actions.loadSuccess(response)) + yield put(userSignActions.load({ address, signature })) + } catch (e) { + yield put(actions.loadFailure(e)) + } +} + +export function* userNonceSagas() { + yield takeEvery(actionTypes.load, watchUserNonce) +} + +export function useGetNonce() { + const dispatch = useDispatch() + + const dispatchGetNonce = useCallback(() => { + const { address } = getAccount() + dispatch(actions.load({ address })) + }, [dispatch]) + + return { dispatchGetNonce } +} + +export { + reducer as userNonceReducer, + actions as userNonceActions, + actionTypes as userNonceActionTypes, +} diff --git a/src/redux/modules/userSign/index.js b/src/redux/modules/userSign/index.js new file mode 100644 index 000000000..beddf9e2a --- /dev/null +++ b/src/redux/modules/userSign/index.js @@ -0,0 +1,28 @@ +import { put, takeEvery } from 'redux-saga/effects' +import ReduxFetchState from 'redux-fetch-state' +import apiPlugin from '../../../services/api' +const API_URL = process.env.REACT_APP_BASE_URL + +const { actions, actionTypes, reducer } = new ReduxFetchState('userSign') + +export function* watchUserSign(action) { + const { address, signature } = action.payload + try { + const response = yield apiPlugin.postData(`${API_URL}/login/${address}`, { + signature: signature, + }) + yield put(actions.loadSuccess(response)) + } catch (e) { + yield put(actions.loadFailure(e)) + } +} + +export function* userSignSagas() { + yield takeEvery(actionTypes.load, watchUserSign) +} + +export { + reducer as userSignReducer, + actions as userSignActions, + actionTypes as userSignActionTypes, +} diff --git a/src/redux/reducer.js b/src/redux/reducer.js new file mode 100644 index 000000000..fa5403a07 --- /dev/null +++ b/src/redux/reducer.js @@ -0,0 +1,12 @@ +import { combineReducers } from 'redux' +import initReducer from './modules/init' +import { userSignReducer } from './modules/userSign' +import { userNonceReducer } from './modules/userNonce' + +const rootReducer = combineReducers({ + init: initReducer, + userSign: userSignReducer, + userNonce: userNonceReducer, +}) + +export default rootReducer diff --git a/src/redux/sagas.js b/src/redux/sagas.js new file mode 100644 index 000000000..be9a9280b --- /dev/null +++ b/src/redux/sagas.js @@ -0,0 +1,7 @@ +import { all } from 'redux-saga/effects' +import { userNonceSagas } from './modules/userNonce' +import { userSignSagas } from './modules/userSign' + +export default function* rootSaga() { + yield all([userNonceSagas(), userSignSagas()]) +} diff --git a/src/redux/store.js b/src/redux/store.js new file mode 100644 index 000000000..7f1afaa25 --- /dev/null +++ b/src/redux/store.js @@ -0,0 +1,16 @@ +import { configureStore } from '@reduxjs/toolkit' +import createSagaMiddleware from 'redux-saga' +import rootReducer from './reducer' +import rootSaga from './sagas' + +const sagaMiddleware = createSagaMiddleware() + +const store = configureStore({ + reducer: rootReducer, + middleware: (getDefaultMiddleware) => + getDefaultMiddleware({ thunk: false, serializableCheck: false }).prepend(sagaMiddleware), +}) + +sagaMiddleware.run(rootSaga) + +export default store From 4f836d0b318a0b7648d3f025080ee4ac549c08eb Mon Sep 17 00:00:00 2001 From: Behnam Jaberi Date: Fri, 28 Jul 2023 20:20:38 +0330 Subject: [PATCH 05/10] Add axios to project --- src/services/api.js | 53 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 src/services/api.js diff --git a/src/services/api.js b/src/services/api.js new file mode 100644 index 000000000..d4b9402c8 --- /dev/null +++ b/src/services/api.js @@ -0,0 +1,53 @@ +import axios from 'axios' + +class ReactApiPlugin { + setAuthToken(token) { + axios.defaults.headers.common['Authorization'] = `Bearer ${token}` + } + + clearAuthToken() { + delete axios.defaults.headers.common['Authorization'] + } + + async putData(url, data, config = {}) { + try { + const response = await axios.put(url, data, config) + return response.data + } catch (error) { + if (error.response) { + throw new Error(error.response.data.message) + } else { + throw new Error('Network error') + } + } + } + + async getData(url, config = {}) { + try { + const response = await axios.get(url, config) + return response.data + } catch (error) { + if (error.response) { + throw new Error(error.response.data.message) + } else { + throw new Error('Network error') + } + } + } + + async postData(url, data, config = {}) { + try { + const response = await axios.post(url, data, config) + return response.data + } catch (error) { + if (error.response) { + throw new Error(error.response.data.message) + } else { + throw new Error('Network error') + } + } + } +} + +const apiPluginInstance = new ReactApiPlugin() +export default apiPluginInstance From 9037686a9f2640f78bec0ba9c0b60091aef502d3 Mon Sep 17 00:00:00 2001 From: Behnam Jaberi Date: Fri, 28 Jul 2023 20:21:42 +0330 Subject: [PATCH 06/10] Update redme file --- README.md | 158 ++++++++---------------------------------------------- 1 file changed, 21 insertions(+), 137 deletions(-) diff --git a/README.md b/README.md index 1185d8047..b8a99090e 100644 --- a/README.md +++ b/README.md @@ -1,55 +1,20 @@ -[![@coreui coreui](https://img.shields.io/badge/@coreui%20-coreui-lightgrey.svg?style=flat-square)](https://github.com/coreui/coreui) -[![npm package][npm-coreui-badge]][npm-coreui] -[![NPM downloads][npm-coreui-download]][npm-coreui] -[![@coreui react](https://img.shields.io/badge/@coreui%20-react-lightgrey.svg?style=flat-square)](https://github.com/coreui/react) -[![npm package][npm-coreui-react-badge]][npm-coreui-react] -[![NPM downloads][npm-coreui-react-download]][npm-coreui-react] - -[npm-coreui]: https://www.npmjs.com/package/@coreui/coreui -[npm-coreui-badge]: https://img.shields.io/npm/v/@coreui/coreui.png?style=flat-square -[npm-coreui-download]: https://img.shields.io/npm/dm/@coreui/coreui.svg?style=flat-square -[npm-coreui-react]: https://www.npmjs.com/package/@coreui/react -[npm-coreui-react-badge]: https://img.shields.io/npm/v/@coreui/react.png?style=flat-square -[npm-coreui-react-download]: https://img.shields.io/npm/dm/@coreui/react.svg?style=flat-square -[npm]: https://www.npmjs.com/package/@coreui/react - -# CoreUI Free React Admin Template - -CoreUI is meant to be the UX game changer. Pure & transparent code is devoid of redundant components, so the app is light enough to offer ultimate user experience. This means mobile devices also, where the navigation is just as easy and intuitive as on a desktop or laptop. The CoreUI Layout API lets you customize your project for almost any device – be it Mobile, Web or WebApp – CoreUI covers them all! - -## Table of Contents - -* [Versions](#versions) -* [CoreUI Pro](#coreui-pro) -* [Quick Start](#quick-start) -* [Installation](#installation) -* [Basic usage](#basic-usage) -* [What's included](#whats-included) -* [Documentation](#documentation) -* [Versioning](#versioning) -* [Creators](#creators) -* [Community](#community) -* [Support CoreUI Development](#support-coreui-development) -* [Copyright and License](#copyright-and-license) - -## Versions - -* [CoreUI Free Bootstrap Admin Template](https://github.com/coreui/coreui-free-bootstrap-admin-template) -* [CoreUI Free Angular Admin Template](https://github.com/coreui/coreui-free-angular-admin-template) -* [CoreUI Free React.js Admin Template](https://github.com/coreui/coreui-free-react-admin-template) -* [CoreUI Free Vue.js Admin Template](https://github.com/coreui/coreui-free-vue-admin-template) - -## CoreUI Pro - -* πŸ’ͺ [CoreUI Pro Angular Admin Template](https://coreui.io/product/angular-dashboard-template/) -* πŸ’ͺ [CoreUI Pro Bootstrap Admin Template](https://coreui.io/product/bootstrap-dashboard-template/) -* πŸ’ͺ [CoreUI Pro React Admin Template](https://coreui.io/product/react-dashboard-template/) -* πŸ’ͺ [CoreUI Pro Vue Admin Template](https://coreui.io/product/vue-dashboard-template/) +# CoreUI Web3 React Admin Template +This project is a web3 version of the CoreUI React admin template. It is a fork of the CoreUI admin template built with React. + +Overview +We have extended the functionality of the original CoreUI template by adding web3 capabilities using the following libraries: + +- RainBowKit - RainbowKit is a React library that makes it easy to add wallet connection to your dapp. It's intuitive, responsive and customizable. +- Axios - Axios is a simple promise based HTTP client for the browser and node.js. Axios provides a simple to use library in a small package with a very extensible interface. +- Redux - For state management. +- Redux Saga - For managing side effects, such as fetching blockchain data. + +The CoreUI template already utilizes React and Bootstrap to provide a robust admin template with a wide range of UI components. ## Quick Start +To get started with the project: -- [Download the latest release](https://github.com/coreui/coreui-free-react-admin-template/archive/refs/heads/main.zip) -- Clone the repo: `git clone https://github.com/coreui/coreui-free-react-admin-template.git` +Clone the repository: git clone https://github.com/treejer/coreui-free-react-admin-template-web3 ### Installation @@ -95,101 +60,20 @@ or $ yarn build ``` -## What's included - -Within the download you'll find the following directories and files, logically grouping common assets and providing both compiled and minified variations. You'll see something like this: - -``` -coreui-free-react-admin-template -β”œβ”€β”€ public/ # static files -β”‚ └── index.html # html template -β”‚ -β”œβ”€β”€ src/ # project root -β”‚ β”œβ”€β”€ assets/ # images, icons, etc. -β”‚ β”œβ”€β”€ components/ # common components - header, footer, sidebar, etc. -β”‚ β”œβ”€β”€ layouts/ # layout containers -β”‚ β”œβ”€β”€ scss/ # scss styles -β”‚ β”œβ”€β”€ views/ # application views -β”‚ β”œβ”€β”€ _nav.js # sidebar navigation config -β”‚ β”œβ”€β”€ App.js -β”‚ β”œβ”€β”€ ... -β”‚ β”œβ”€β”€ index.js -β”‚ β”œβ”€β”€ routes.js # routes config -β”‚ └── store.js # template state example -β”‚ -└── package.json -``` +# Env Setup +Duplicate the environment file and modify its variable values. +cp .env.example .env ## Documentation The documentation for the CoreUI Admin Template is hosted at our website [CoreUI for React](https://coreui.io/react/) -## Versioning - -For transparency into our release cycle and in striving to maintain backward compatibility, CoreUI Free Admin Template is maintained under [the Semantic Versioning guidelines](http://semver.org/). - -See [the Releases section of our project](https://github.com/coreui/coreui-free-react-admin-template/releases) for changelogs for each release version. - -## Creators - -**Łukasz Holeczek** -* -* -* - -**CoreUI team** -* https://github.com/orgs/coreui/people - -## Community - -Get updates on CoreUI's development and chat with the project maintainers and community members. - -- Follow [@core_ui on Twitter](https://twitter.com/core_ui). -- Read and subscribe to [CoreUI Blog](https://coreui.ui/blog/). - -## Support CoreUI Development - -CoreUI is an MIT-licensed open source project and is completely free to use. However, the amount of effort needed to maintain and develop new features for the project is not sustainable without proper financial backing. You can support development by buying the [CoreUI PRO](https://coreui.io/pricing/) or by becoming a sponsor via [Open Collective](https://opencollective.com/coreui/). - - -### Platinum Sponsors +### About -Support this project by [becoming a Platinum Sponsor](https://opencollective.com/coreui/contribute/platinum-sponsor-40959/). A large company logo will be added here with a link to your website. +This project is built and maintained by the [Treejer Team](https://github.com/treejer). The source code is available on [GitHub]([https://github.com/treejer](https://github.com/treejer/coreui-free-react-admin-template-web3)). +Please feel free to reach out if you have any questions or need further assistance. We are happy to help! - - -### Gold Sponsors - -Support this project by [becoming a Gold Sponsor](https://opencollective.com/coreui/contribute/gold-sponsor-40960/). A big company logo will be added here with a link to your website. - - - -### Silver Sponsors - -Support this project by [becoming a Silver Sponsor](https://opencollective.com/coreui/contribute/silver-sponsor-40967/). A medium company logo will be added here with a link to your website. - - - -### Bronze Sponsors - -Support this project by [becoming a Bronze Sponsor](https://opencollective.com/coreui/contribute/bronze-sponsor-40966/). The company avatar will show up here with a link to your OpenCollective Profile. - - - -### Backers - -Thanks to all the backers and sponsors! Support this project by [becoming a backer](https://opencollective.com/coreui/contribute/backer-40965/). - - - - - -## Copyright and License - -copyright 2023 creativeLabs Łukasz Holeczek. +## Documentation - Code released under [the MIT license](https://github.com/coreui/coreui-free-react-admin-template/blob/master/LICENSE). -There is only one limitation you can't can’t re-distribute the CoreUI as stock. You can’t do this if you modify the CoreUI. In past we faced some problems with persons who tried to sell CoreUI based templates. - From d24e644fe0620fc96ef0ac38bc59c17e7aedeaa6 Mon Sep 17 00:00:00 2001 From: Behnam Jaberi Date: Fri, 28 Jul 2023 20:22:21 +0330 Subject: [PATCH 07/10] Update package.json file and install necessary packages --- package.json | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/package.json b/package.json index f54e6f2e9..02941661d 100644 --- a/package.json +++ b/package.json @@ -30,6 +30,8 @@ "@coreui/react-chartjs": "2.1.3", "@coreui/utils": "2.0.2", "@rainbow-me/rainbowkit": "1.0.7", + "@reduxjs/toolkit": "1.9.5", + "axios": "1.4.0", "chart.js": "3.9.1", "classnames": "2.3.2", "core-js": "3.31.0", @@ -40,6 +42,8 @@ "react-redux": "8.1.1", "react-router-dom": "6.14.0", "redux": "4.2.1", + "redux-fetch-state": "0.2.4", + "redux-saga": "1.2.3", "simplebar-react": "2.4.3", "viem": "1.4.2", "wagmi": "1.3.9" From 1db84355e8e9a4ff8eaab38df72175f9cdedfd83 Mon Sep 17 00:00:00 2001 From: Behnam Jaberi Date: Fri, 28 Jul 2023 20:23:09 +0330 Subject: [PATCH 08/10] Add rainbow button to header and change sidebar show action --- src/components/AppHeader.js | 40 +++++++------------------------- src/components/rainbow/button.js | 36 ++++++++++++++++++++++++---- 2 files changed, 40 insertions(+), 36 deletions(-) diff --git a/src/components/AppHeader.js b/src/components/AppHeader.js index 3d26dabb3..6649a915e 100644 --- a/src/components/AppHeader.js +++ b/src/components/AppHeader.js @@ -1,6 +1,5 @@ import React from 'react' import { NavLink } from 'react-router-dom' -import { useSelector, useDispatch } from 'react-redux' import { CContainer, CHeader, @@ -13,39 +12,19 @@ import { } from '@coreui/react' import CIcon from '@coreui/icons-react' import { cilBell, cilEnvelopeOpen, cilList, cilMenu } from '@coreui/icons' - +import { useToggleSidebar } from '../redux/modules/init' import { AppBreadcrumb } from './index' -import { AuthHeaderDropdown } from './header/auth/index' +import { AppHeaderDropdown } from './header/index' import { logo } from 'src/assets/brand/logo' - -// Wagnumi Auth // -import { EthereumClient, w3mConnectors, w3mProvider } from '@web3modal/ethereum' -import { Web3Modal } from '@web3modal/react' -import { configureChains, createConfig, WagmiConfig } from 'wagmi' -import { arbitrum, mainnet, polygon } from 'wagmi/chains' - -const chains = [arbitrum, mainnet, polygon] -const projectId = 'YOUR_PROJECT_ID' - -const { publicClient } = configureChains(chains, [w3mProvider({ projectId })]) -const wagmiConfig = createConfig({ - autoConnect: true, - connectors: w3mConnectors({ projectId, version: 1, chains }), - publicClient -}) +import { WalletButton } from './rainbow/index' const AppHeader = () => { - const dispatch = useDispatch() - const ethereumClient = new EthereumClient(wagmiConfig, chains) - const sidebarShow = useSelector((state) => state.sidebarShow) + const { toggleSidebar } = useToggleSidebar() return ( - dispatch({ type: 'set', sidebarShow: !sidebarShow })} - > + @@ -64,12 +43,8 @@ const AppHeader = () => { Settings - - - - - + @@ -88,6 +63,9 @@ const AppHeader = () => { + + + diff --git a/src/components/rainbow/button.js b/src/components/rainbow/button.js index adc25b21c..7c96857e4 100644 --- a/src/components/rainbow/button.js +++ b/src/components/rainbow/button.js @@ -1,8 +1,11 @@ import React, { useEffect } from 'react' -import { darkTheme, RainbowKitProvider, ConnectButton } from '@rainbow-me/rainbowkit' -import { configureChains } from 'wagmi' +import { CButton } from '@coreui/react' +import { useSelector } from 'react-redux' +import { RainbowKitProvider, ConnectButton } from '@rainbow-me/rainbowkit' +import { configureChains, useAccount } from 'wagmi' import { mainnet, polygon, optimism, arbitrum, zora } from 'wagmi/chains' import { alchemyProvider } from 'wagmi/providers/alchemy' +import { useGetNonce } from '../../redux/modules/userNonce' import { publicProvider } from 'wagmi/providers/public' import '@rainbow-me/rainbowkit/styles.css' @@ -12,10 +15,33 @@ const { chains } = configureChains( ) const RainBowButton = () => { + const { address } = useAccount() + const { dispatchGetNonce } = useGetNonce() + const userToken = useSelector((state) => state.userSign?.data?.access_token) + + useEffect(() => { + if (address) { + dispatchGetNonce(address) + } + }, [address, dispatchGetNonce]) + + const handleSignInWallet = () => { + if (address) { + dispatchGetNonce(address) + } + } + return ( - - - + <> + {!userToken && address && ( + + Sign In Wallet + + )} + + + + ) } From ce581066d9104411aed466003a346cbf97bbaaaa Mon Sep 17 00:00:00 2001 From: Behnam Jaberi Date: Fri, 28 Jul 2023 20:23:33 +0330 Subject: [PATCH 09/10] Update sidebar acions from redux --- src/components/AppSidebar.js | 26 +++++--------------------- 1 file changed, 5 insertions(+), 21 deletions(-) diff --git a/src/components/AppSidebar.js b/src/components/AppSidebar.js index a75bf6523..91437a159 100644 --- a/src/components/AppSidebar.js +++ b/src/components/AppSidebar.js @@ -1,34 +1,21 @@ import React from 'react' -import { useSelector, useDispatch } from 'react-redux' - +import { useSelector } from 'react-redux' import { CSidebar, CSidebarBrand, CSidebarNav, CSidebarToggler } from '@coreui/react' import CIcon from '@coreui/icons-react' - import { AppSidebarNav } from './AppSidebarNav' - import { logoNegative } from 'src/assets/brand/logo-negative' import { sygnet } from 'src/assets/brand/sygnet' - import SimpleBar from 'simplebar-react' import 'simplebar/dist/simplebar.min.css' - -// sidebar nav config import navigation from '../_nav' +import { useToggleSidebar } from '../redux/modules/init' const AppSidebar = () => { - const dispatch = useDispatch() const unfoldable = useSelector((state) => state.sidebarUnfoldable) - const sidebarShow = useSelector((state) => state.sidebarShow) + const { sidebarShow, toggleSidebar } = useToggleSidebar() return ( - { - dispatch({ type: 'set', sidebarShow: visible }) - }} - > + @@ -38,10 +25,7 @@ const AppSidebar = () => { - dispatch({ type: 'set', sidebarUnfoldable: !unfoldable })} - /> + ) } From 2e17bdf184f35b2f7f627e8debfab9807420a8e5 Mon Sep 17 00:00:00 2001 From: Behnam Jaberi Date: Fri, 28 Jul 2023 20:23:54 +0330 Subject: [PATCH 10/10] Update store address --- src/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/index.js b/src/index.js index d19a3bcd3..24e08e724 100644 --- a/src/index.js +++ b/src/index.js @@ -5,7 +5,7 @@ import { createRoot } from 'react-dom/client' import App from './App' import reportWebVitals from './reportWebVitals' import { Provider } from 'react-redux' -import store from './store' +import store from './redux/store' createRoot(document.getElementById('root')).render(