project: init
This commit is contained in:
parent
961623c75d
commit
4b53a4f279
13
.editorconfig
Normal file
13
.editorconfig
Normal file
@ -0,0 +1,13 @@
|
||||
# editorconfig.org
|
||||
root = true
|
||||
|
||||
[*]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
end_of_line = lf
|
||||
charset = utf-8
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
||||
|
||||
[*.md]
|
||||
trim_trailing_whitespace = false
|
15
.eslintrc.js
Normal file
15
.eslintrc.js
Normal file
@ -0,0 +1,15 @@
|
||||
module.exports = {
|
||||
root: true,
|
||||
env: {
|
||||
browser: true,
|
||||
node: true,
|
||||
},
|
||||
parserOptions: {
|
||||
parser: '@babel/eslint-parser',
|
||||
requireConfigFile: false,
|
||||
},
|
||||
extends: ['@nuxtjs', 'plugin:nuxt/recommended', 'prettier'],
|
||||
plugins: [],
|
||||
// add your custom rules here
|
||||
rules: {},
|
||||
}
|
90
.gitignore
vendored
Normal file
90
.gitignore
vendored
Normal file
@ -0,0 +1,90 @@
|
||||
# Created by .ignore support plugin (hsz.mobi)
|
||||
### Node template
|
||||
# Logs
|
||||
/logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
|
||||
# Runtime data
|
||||
pids
|
||||
*.pid
|
||||
*.seed
|
||||
*.pid.lock
|
||||
|
||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||
lib-cov
|
||||
|
||||
# Coverage directory used by tools like istanbul
|
||||
coverage
|
||||
|
||||
# nyc test coverage
|
||||
.nyc_output
|
||||
|
||||
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
|
||||
.grunt
|
||||
|
||||
# Bower dependency directory (https://bower.io/)
|
||||
bower_components
|
||||
|
||||
# node-waf configuration
|
||||
.lock-wscript
|
||||
|
||||
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
||||
build/Release
|
||||
|
||||
# Dependency directories
|
||||
node_modules/
|
||||
jspm_packages/
|
||||
|
||||
# TypeScript v1 declaration files
|
||||
typings/
|
||||
|
||||
# Optional npm cache directory
|
||||
.npm
|
||||
|
||||
# Optional eslint cache
|
||||
.eslintcache
|
||||
|
||||
# Optional REPL history
|
||||
.node_repl_history
|
||||
|
||||
# Output of 'npm pack'
|
||||
*.tgz
|
||||
|
||||
# Yarn Integrity file
|
||||
.yarn-integrity
|
||||
|
||||
# dotenv environment variables file
|
||||
.env
|
||||
|
||||
# parcel-bundler cache (https://parceljs.org/)
|
||||
.cache
|
||||
|
||||
# next.js build output
|
||||
.next
|
||||
|
||||
# nuxt.js build output
|
||||
.nuxt
|
||||
|
||||
# Nuxt generate
|
||||
dist
|
||||
|
||||
# vuepress build output
|
||||
.vuepress/dist
|
||||
|
||||
# Serverless directories
|
||||
.serverless
|
||||
|
||||
# IDE / Editor
|
||||
.idea
|
||||
|
||||
# Service worker
|
||||
sw.*
|
||||
|
||||
# macOS
|
||||
.DS_Store
|
||||
|
||||
# Vim swap files
|
||||
*.swp
|
96
.prettierignore
Normal file
96
.prettierignore
Normal file
@ -0,0 +1,96 @@
|
||||
###
|
||||
# Place your Prettier ignore content here
|
||||
|
||||
###
|
||||
# .gitignore content is duplicated here due to https://github.com/prettier/prettier/issues/8506
|
||||
|
||||
# Created by .ignore support plugin (hsz.mobi)
|
||||
### Node template
|
||||
# Logs
|
||||
/logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
|
||||
# Runtime data
|
||||
pids
|
||||
*.pid
|
||||
*.seed
|
||||
*.pid.lock
|
||||
|
||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||
lib-cov
|
||||
|
||||
# Coverage directory used by tools like istanbul
|
||||
coverage
|
||||
|
||||
# nyc test coverage
|
||||
.nyc_output
|
||||
|
||||
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
|
||||
.grunt
|
||||
|
||||
# Bower dependency directory (https://bower.io/)
|
||||
bower_components
|
||||
|
||||
# node-waf configuration
|
||||
.lock-wscript
|
||||
|
||||
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
||||
build/Release
|
||||
|
||||
# Dependency directories
|
||||
node_modules/
|
||||
jspm_packages/
|
||||
|
||||
# TypeScript v1 declaration files
|
||||
typings/
|
||||
|
||||
# Optional npm cache directory
|
||||
.npm
|
||||
|
||||
# Optional eslint cache
|
||||
.eslintcache
|
||||
|
||||
# Optional REPL history
|
||||
.node_repl_history
|
||||
|
||||
# Output of 'npm pack'
|
||||
*.tgz
|
||||
|
||||
# Yarn Integrity file
|
||||
.yarn-integrity
|
||||
|
||||
# dotenv environment variables file
|
||||
.env
|
||||
|
||||
# parcel-bundler cache (https://parceljs.org/)
|
||||
.cache
|
||||
|
||||
# next.js build output
|
||||
.next
|
||||
|
||||
# nuxt.js build output
|
||||
.nuxt
|
||||
|
||||
# Nuxt generate
|
||||
dist
|
||||
|
||||
# vuepress build output
|
||||
.vuepress/dist
|
||||
|
||||
# Serverless directories
|
||||
.serverless
|
||||
|
||||
# IDE / Editor
|
||||
.idea
|
||||
|
||||
# Service worker
|
||||
sw.*
|
||||
|
||||
# macOS
|
||||
.DS_Store
|
||||
|
||||
# Vim swap files
|
||||
*.swp
|
4
.prettierrc
Normal file
4
.prettierrc
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
"semi": false,
|
||||
"singleQuote": true
|
||||
}
|
18
README.md
Normal file
18
README.md
Normal file
@ -0,0 +1,18 @@
|
||||
# CIC Dashboard
|
||||
|
||||
## Build Setup
|
||||
|
||||
```bash
|
||||
# install dependencies
|
||||
$ yarn install
|
||||
|
||||
# serve with hot reload at localhost:3000
|
||||
$ yarn dev
|
||||
|
||||
# build for production and launch server
|
||||
$ yarn build
|
||||
$ yarn start
|
||||
|
||||
# generate static project
|
||||
$ yarn generate
|
||||
```
|
BIN
assets/gecon_logo.png
Normal file
BIN
assets/gecon_logo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 61 KiB |
10
assets/variables.scss
Normal file
10
assets/variables.scss
Normal file
@ -0,0 +1,10 @@
|
||||
@import url('https://fonts.googleapis.com/css2?family=Open+Sans:wght@400;600;700&display=swap');
|
||||
|
||||
$title-font: 'Open Sans';
|
||||
$body-font-family: 'Open Sans';
|
||||
|
||||
$btn-font-weight: 600;
|
||||
|
||||
.v-application {
|
||||
font-family: $title-font;
|
||||
}
|
97
components/base/DashboardSidebar.vue
Normal file
97
components/base/DashboardSidebar.vue
Normal file
@ -0,0 +1,97 @@
|
||||
<template>
|
||||
<div>
|
||||
<v-app-bar dark height="50" flat color="secondary" app>
|
||||
<v-app-bar-nav-icon
|
||||
color="primary"
|
||||
class="hidden-lg-and-up"
|
||||
@click.stop="drawer = !drawer"
|
||||
></v-app-bar-nav-icon>
|
||||
<div></div>
|
||||
</v-app-bar>
|
||||
<v-navigation-drawer
|
||||
v-model="drawer"
|
||||
app
|
||||
dark
|
||||
floating
|
||||
class="elevation-4"
|
||||
color="primary"
|
||||
width="200"
|
||||
>
|
||||
<div class="d-flex flex-column align-center">
|
||||
<div class="pa-3">
|
||||
<v-img :src="require('@/assets/gecon_logo.png')" max-width="65px" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<v-list class="overline" dense>
|
||||
<v-list-item to="/">
|
||||
<v-list-item-icon>
|
||||
<v-icon>mdi-view-dashboard</v-icon>
|
||||
</v-list-item-icon>
|
||||
|
||||
<v-list-item-content>
|
||||
<v-list-item-title>Home</v-list-item-title>
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
|
||||
<v-list-item disabled to="/tokens">
|
||||
<v-list-item-icon>
|
||||
<v-icon>mdi-cash-multiple</v-icon>
|
||||
</v-list-item-icon>
|
||||
|
||||
<v-list-item-content>
|
||||
<v-list-item-title>Tokens</v-list-item-title>
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
|
||||
<v-list-item disabled to="/accounts">
|
||||
<v-list-item-icon>
|
||||
<v-icon>mdi-wallet</v-icon>
|
||||
</v-list-item-icon>
|
||||
|
||||
<v-list-item-content>
|
||||
<v-list-item-title>Accounts</v-list-item-title>
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
|
||||
<v-list-item disabled to="/transactions">
|
||||
<v-list-item-icon>
|
||||
<v-icon>mdi-tray-full</v-icon>
|
||||
</v-list-item-icon>
|
||||
|
||||
<v-list-item-content>
|
||||
<v-list-item-title>Transactions</v-list-item-title>
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
|
||||
<v-list-item disabled to="/social-network">
|
||||
<v-list-item-icon>
|
||||
<v-icon>mdi-account-group</v-icon>
|
||||
</v-list-item-icon>
|
||||
|
||||
<v-list-item-content>
|
||||
<v-list-item-title>Social Network</v-list-item-title>
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
</v-list>
|
||||
|
||||
<template #append>
|
||||
<div class="pa-2 text-center">
|
||||
<v-chip color="success" small label>
|
||||
<b>Grassroots Economics</b>
|
||||
</v-chip>
|
||||
</div>
|
||||
</template>
|
||||
</v-navigation-drawer>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
drawer: null,
|
||||
}
|
||||
},
|
||||
}
|
||||
</script>
|
73
components/charts/LineChart.vue
Normal file
73
components/charts/LineChart.vue
Normal file
@ -0,0 +1,73 @@
|
||||
<template>
|
||||
<client-only>
|
||||
<v-card elevation="0" outlined>
|
||||
<v-card-text>
|
||||
<v-card-subtitle class="black--text">
|
||||
{{ chartTitle }}
|
||||
</v-card-subtitle>
|
||||
<ApexChart
|
||||
height="250"
|
||||
width="100%"
|
||||
type="area"
|
||||
:options="chartOptions"
|
||||
:series="seriesData"
|
||||
></ApexChart>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
</client-only>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
chartData: {
|
||||
type: Array,
|
||||
required: true,
|
||||
},
|
||||
chartTitle: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
chartOptions: {
|
||||
tooltip: {
|
||||
y: {
|
||||
title: {
|
||||
formatter: () => 'count',
|
||||
},
|
||||
},
|
||||
},
|
||||
chart: {
|
||||
toolbar: {
|
||||
show: false,
|
||||
},
|
||||
type: 'line',
|
||||
zoom: {
|
||||
enabled: false,
|
||||
},
|
||||
},
|
||||
dataLabels: {
|
||||
enabled: true,
|
||||
},
|
||||
grid: {
|
||||
row: {
|
||||
colors: ['#f3f3f3', 'transparent'],
|
||||
opacity: 0.5,
|
||||
},
|
||||
},
|
||||
xaxis: {
|
||||
type: 'datetime',
|
||||
},
|
||||
},
|
||||
|
||||
seriesData: [
|
||||
{
|
||||
data: this.chartData,
|
||||
},
|
||||
],
|
||||
}
|
||||
},
|
||||
}
|
||||
</script>
|
13
jsconfig.json
Normal file
13
jsconfig.json
Normal file
@ -0,0 +1,13 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"~/*": ["./*"],
|
||||
"@/*": ["./*"],
|
||||
"~~/*": ["./*"],
|
||||
"@@/*": ["./*"]
|
||||
}
|
||||
},
|
||||
"exclude": ["node_modules", ".nuxt", "dist"]
|
||||
}
|
||||
|
20
layouts/default.vue
Normal file
20
layouts/default.vue
Normal file
@ -0,0 +1,20 @@
|
||||
<template>
|
||||
<v-app>
|
||||
<Sidebar />
|
||||
<v-main class="secondary">
|
||||
<v-container fluid>
|
||||
<nuxt />
|
||||
</v-container>
|
||||
</v-main>
|
||||
</v-app>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Sidebar from '~/components/base/DashboardSidebar.vue'
|
||||
export default {
|
||||
name: 'DefaultLayout',
|
||||
components: {
|
||||
Sidebar,
|
||||
},
|
||||
}
|
||||
</script>
|
46
layouts/error.vue
Normal file
46
layouts/error.vue
Normal file
@ -0,0 +1,46 @@
|
||||
<template>
|
||||
<v-app>
|
||||
<v-main class="secondary">
|
||||
<v-container fluid class="text-center mx-auto">
|
||||
<h1 v-if="error.statusCode === 404">
|
||||
{{ pageNotFound }}
|
||||
</h1>
|
||||
<h1 v-else>
|
||||
{{ otherError }}
|
||||
</h1>
|
||||
<NuxtLink to="/"> Home page </NuxtLink>
|
||||
</v-container>
|
||||
</v-main>
|
||||
</v-app>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'EmptyLayout',
|
||||
props: {
|
||||
error: {
|
||||
type: Object,
|
||||
default: null,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
pageNotFound: '404: Page Not Found',
|
||||
otherError: 'An error occurred',
|
||||
}
|
||||
},
|
||||
head() {
|
||||
const title =
|
||||
this.error.statusCode === 404 ? this.pageNotFound : this.otherError
|
||||
return {
|
||||
title,
|
||||
}
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
h1 {
|
||||
font-size: 20px;
|
||||
}
|
||||
</style>
|
47
nuxt.config.js
Normal file
47
nuxt.config.js
Normal file
@ -0,0 +1,47 @@
|
||||
import colors from 'vuetify/es5/util/colors'
|
||||
|
||||
export default {
|
||||
target: 'static',
|
||||
head: {
|
||||
titleTemplate: '%s - cic-dashboard',
|
||||
title: 'Sarafu Network Dashboard',
|
||||
htmlAttrs: {
|
||||
lang: 'en',
|
||||
},
|
||||
meta: [
|
||||
{ charset: 'utf-8' },
|
||||
{ name: 'viewport', content: 'width=device-width, initial-scale=1' },
|
||||
{ hid: 'description', name: 'description', content: '' },
|
||||
{ name: 'format-detection', content: 'telephone=no' },
|
||||
],
|
||||
link: [{ rel: 'icon', type: 'image/x-icon', href: '/favicon-32x32.png' }],
|
||||
},
|
||||
css: [],
|
||||
plugins: [{ src: '~/plugins/apexcharts.js', ssr: false }],
|
||||
components: true,
|
||||
buildModules: ['@nuxtjs/eslint-module', '@nuxtjs/vuetify'],
|
||||
modules: ['@nuxtjs/axios'],
|
||||
|
||||
axios: {
|
||||
baseURL: 'https://data-warehouse.sarafu.network/dashboard/',
|
||||
},
|
||||
vuetify: {
|
||||
customVariables: ['~/assets/variables.scss'],
|
||||
treeShake: true,
|
||||
theme: {
|
||||
dark: false,
|
||||
themes: {
|
||||
light: {
|
||||
primary: '#222731',
|
||||
secondary: '#e1e5ea',
|
||||
accent: colors.grey.darken3,
|
||||
info: colors.teal.lighten1,
|
||||
warning: colors.amber.base,
|
||||
error: colors.deepOrange.accent4,
|
||||
success: colors.green.accent3,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
build: {},
|
||||
}
|
41
package.json
Normal file
41
package.json
Normal file
@ -0,0 +1,41 @@
|
||||
{
|
||||
"name": "cic-dashboard",
|
||||
"version": "1.0.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "nuxt",
|
||||
"build": "nuxt build",
|
||||
"start": "nuxt start",
|
||||
"generate": "nuxt generate",
|
||||
"lint:js": "eslint --ext \".js,.vue\" --ignore-path .gitignore .",
|
||||
"lint:prettier": "prettier --check .",
|
||||
"lint": "yarn lint:js && yarn lint:prettier",
|
||||
"lintfix": "prettier --write --list-different . && yarn lint:js --fix"
|
||||
},
|
||||
"dependencies": {
|
||||
"@nuxtjs/axios": "^5.13.6",
|
||||
"apexcharts": "^3.35.2",
|
||||
"core-js": "^3.19.3",
|
||||
"echarts": "^5.3.2",
|
||||
"nuxt": "^2.15.8",
|
||||
"vue": "^2.6.14",
|
||||
"vue-apexcharts": "^1.6.2",
|
||||
"vue-echarts": "^6.0.2",
|
||||
"vue-server-renderer": "^2.6.14",
|
||||
"vue-template-compiler": "^2.6.14",
|
||||
"vuetify": "^2.6.1",
|
||||
"webpack": "^4.46.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/eslint-parser": "^7.16.3",
|
||||
"@nuxtjs/composition-api": "^0.32.0",
|
||||
"@nuxtjs/eslint-config": "^8.0.0",
|
||||
"@nuxtjs/eslint-module": "^3.0.2",
|
||||
"@nuxtjs/vuetify": "^1.12.3",
|
||||
"eslint": "^8.4.1",
|
||||
"eslint-config-prettier": "^8.3.0",
|
||||
"eslint-plugin-nuxt": "^3.1.0",
|
||||
"eslint-plugin-vue": "^8.2.0",
|
||||
"prettier": "^2.5.1"
|
||||
}
|
||||
}
|
96
pages/index.vue
Normal file
96
pages/index.vue
Normal file
@ -0,0 +1,96 @@
|
||||
<template>
|
||||
<v-container>
|
||||
<v-menu
|
||||
v-model="menu"
|
||||
:close-on-content-click="false"
|
||||
transition="scale-transition"
|
||||
offset-y
|
||||
min-width="100px"
|
||||
>
|
||||
<template #activator="{ on, attrs }">
|
||||
<v-text-field
|
||||
v-model="dateRangeText"
|
||||
label="Date Range"
|
||||
persistent-hint
|
||||
prepend-icon="mdi-calendar"
|
||||
readonly
|
||||
v-bind="attrs"
|
||||
v-on="on"
|
||||
></v-text-field>
|
||||
</template>
|
||||
<v-date-picker
|
||||
v-model="dates"
|
||||
range
|
||||
no-title
|
||||
@input="menu = false"
|
||||
></v-date-picker>
|
||||
</v-menu>
|
||||
<v-row class="d-flex justify-space-beetween">
|
||||
<v-col cols="12" md="6" lg="6">
|
||||
<line-chart chart-title="New Registrations" :chart-data="regCount" />
|
||||
</v-col>
|
||||
<v-col cols="12" md="6" lg="6">
|
||||
<line-chart chart-title="Transactions Count" :chart-data="txCount" />
|
||||
</v-col>
|
||||
</v-row>
|
||||
</v-container>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import LineChart from '~/components/charts/LineChart.vue'
|
||||
|
||||
export default {
|
||||
name: 'IndexPage',
|
||||
components: {
|
||||
LineChart,
|
||||
},
|
||||
async asyncData({ $axios }) {
|
||||
const dateToday = new Date()
|
||||
const dateStart = new Date(dateToday.getFullYear(), dateToday.getMonth(), 1)
|
||||
|
||||
const start = dateStart.toISOString().split('T')[0]
|
||||
const end = dateToday.toISOString().split('T')[0]
|
||||
|
||||
const [regCount, txCount] = await Promise.all([
|
||||
$axios.get(`/new-registrations?from=${start}&to=${end}`),
|
||||
$axios.get(`/transactions-count?from=${start}&to=${end}`),
|
||||
])
|
||||
|
||||
return {
|
||||
regCount: regCount.data,
|
||||
txCount: txCount.data,
|
||||
dates: [start, end],
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
menu: false,
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
dateRangeText() {
|
||||
return this.dates.join(' ~ ')
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
date(val) {
|
||||
this.dateFormatted = this.formatDate(this.date)
|
||||
},
|
||||
},
|
||||
|
||||
methods: {
|
||||
formatDate(date) {
|
||||
if (!date) return null
|
||||
|
||||
const [year, month, day] = date.split('-')
|
||||
return `${month}/${day}/${year}`
|
||||
},
|
||||
parseDate(date) {
|
||||
if (!date) return null
|
||||
|
||||
const [month, day, year] = date.split('/')
|
||||
return `${year}-${month.padStart(2, '0')}-${day.padStart(2, '0')}`
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
5
plugins/apexcharts.js
Normal file
5
plugins/apexcharts.js
Normal file
@ -0,0 +1,5 @@
|
||||
import Vue from 'vue'
|
||||
import VueApexCharts from 'vue-apexcharts'
|
||||
|
||||
Vue.use(VueApexCharts)
|
||||
Vue.component('ApexChart', VueApexCharts)
|
BIN
static/favicon-32x32.png
Normal file
BIN
static/favicon-32x32.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.6 KiB |
Loading…
Reference in New Issue
Block a user