mirror of
https://github.com/IT4Change/gradido.git
synced 2025-12-13 07:45:54 +00:00
Merge pull request #115 from gradido/work-components-tests
store aufräumen teil 1
This commit is contained in:
commit
2a493332b7
21
frontend/DEV-README.md
Normal file
21
frontend/DEV-README.md
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
DEV README von Alex
|
||||||
|
|
||||||
|
default Page:
|
||||||
|
´´´
|
||||||
|
<template>
|
||||||
|
<div>default</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'default',
|
||||||
|
data() {
|
||||||
|
return {}
|
||||||
|
},
|
||||||
|
methods: {},
|
||||||
|
watch: {},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
´´´
|
||||||
|
|
||||||
@ -32,6 +32,13 @@ export default {
|
|||||||
components: {
|
components: {
|
||||||
ParticlesBg,
|
ParticlesBg,
|
||||||
},
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
session_id: null,
|
||||||
|
email: '',
|
||||||
|
language: 'en',
|
||||||
|
}
|
||||||
|
},
|
||||||
created() {
|
created() {
|
||||||
//console.log('xx', $cookies.get('gdd_lang'))
|
//console.log('xx', $cookies.get('gdd_lang'))
|
||||||
//console.log('%cWillkommen bei Gradido %cgreen text', 'font-weight:bold', 'color: green')
|
//console.log('%cWillkommen bei Gradido %cgreen text', 'font-weight:bold', 'color: green')
|
||||||
|
|||||||
@ -2,7 +2,7 @@ import DashboardLayout from '@/views/Layout/DashboardLayout.vue'
|
|||||||
import AuthLayoutGDD from '@/views/Layout/AuthLayout_gdd.vue'
|
import AuthLayoutGDD from '@/views/Layout/AuthLayout_gdd.vue'
|
||||||
import AuthLayout from '@/views/Layout/AuthLayout.vue'
|
import AuthLayout from '@/views/Layout/AuthLayout.vue'
|
||||||
|
|
||||||
// import NotFound from '@/views/NotFoundPage.vue'
|
import NotFound from '@/views/NotFoundPage.vue'
|
||||||
|
|
||||||
const routes = [
|
const routes = [
|
||||||
{
|
{
|
||||||
@ -31,6 +31,11 @@ const routes = [
|
|||||||
name: 'Explorer',
|
name: 'Explorer',
|
||||||
component: () => import('../views/Pages/Explorer.vue'),
|
component: () => import('../views/Pages/Explorer.vue'),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: '/icons',
|
||||||
|
name: 'Icons',
|
||||||
|
component: () => import('../views/Icons.vue'),
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -63,10 +68,9 @@ const routes = [
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
,
|
|
||||||
{
|
{
|
||||||
path: '/',
|
path: '/admin',
|
||||||
redirect: 'AdminOverview',
|
redirect: 'admin',
|
||||||
component: AuthLayout,
|
component: AuthLayout,
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
@ -79,6 +83,7 @@ const routes = [
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
{ path: '*', component: NotFound },
|
||||||
]
|
]
|
||||||
|
|
||||||
export default routes
|
export default routes
|
||||||
|
|||||||
@ -1,33 +0,0 @@
|
|||||||
import Vue from 'vue'
|
|
||||||
import Router from 'vue-router'
|
|
||||||
import DashboardLayout from '../views/Starter/SampleLayout.vue'
|
|
||||||
import Starter from '../views/Starter/SamplePage.vue'
|
|
||||||
|
|
||||||
Vue.use(Router)
|
|
||||||
|
|
||||||
export default new Router({
|
|
||||||
routes: [
|
|
||||||
{
|
|
||||||
path: '/',
|
|
||||||
name: 'home',
|
|
||||||
redirect: '/dashboard',
|
|
||||||
component: DashboardLayout,
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
path: 'dashboard',
|
|
||||||
name: 'dashboard',
|
|
||||||
components: { default: Starter },
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
scrollBehavior: (to, from, savedPosition) => {
|
|
||||||
if (savedPosition) {
|
|
||||||
return savedPosition
|
|
||||||
}
|
|
||||||
if (to.hash) {
|
|
||||||
return { selector: to.hash }
|
|
||||||
}
|
|
||||||
return { x: 0, y: 0 }
|
|
||||||
},
|
|
||||||
})
|
|
||||||
@ -8,28 +8,16 @@ import communityAPI from '../apis/communityAPI'
|
|||||||
export const store = new Vuex.Store({
|
export const store = new Vuex.Store({
|
||||||
state: {
|
state: {
|
||||||
session_id: null,
|
session_id: null,
|
||||||
email: null,
|
email: '',
|
||||||
language: 'en',
|
language: 'en',
|
||||||
sizeDE: 'normal',
|
sizeDE: 'normal',
|
||||||
sizeGB: 'big',
|
sizeGB: 'big',
|
||||||
loginfail: false,
|
loginfail: false,
|
||||||
row_form: true,
|
|
||||||
row_check: false,
|
|
||||||
row_thx: false,
|
|
||||||
user: {
|
user: {
|
||||||
name: '',
|
name: '',
|
||||||
balance: 0,
|
balance: 0,
|
||||||
balance_gdt: 0,
|
balance_gdt: 0,
|
||||||
},
|
},
|
||||||
ajaxCreateData: {
|
|
||||||
session_id: '',
|
|
||||||
email: '',
|
|
||||||
amount: 0,
|
|
||||||
target_date: '',
|
|
||||||
memo: '',
|
|
||||||
auto_sign: true,
|
|
||||||
},
|
|
||||||
transactions: [],
|
|
||||||
modals: false,
|
modals: false,
|
||||||
optionAxios: {
|
optionAxios: {
|
||||||
headers: {
|
headers: {
|
||||||
@ -39,11 +27,7 @@ export const store = new Vuex.Store({
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
getters: {
|
getters: {},
|
||||||
//isLoggedIn: (state /*, getters */) => {
|
|
||||||
// return state.session_id !== null;
|
|
||||||
//}
|
|
||||||
},
|
|
||||||
// Syncronous mutation of the state
|
// Syncronous mutation of the state
|
||||||
mutations: {
|
mutations: {
|
||||||
language: (state, language) => {
|
language: (state, language) => {
|
||||||
@ -78,10 +62,6 @@ export const store = new Vuex.Store({
|
|||||||
//console.log('mutation: user_balance_gdt')
|
//console.log('mutation: user_balance_gdt')
|
||||||
state.user.balance_gdt = balance / 10000
|
state.user.balance_gdt = balance / 10000
|
||||||
},
|
},
|
||||||
transactions: (state, transactions) => {
|
|
||||||
//console.log('mutation: transactions')
|
|
||||||
state.transactions = transactions
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
// Asyncronous actions - used for api calls
|
// Asyncronous actions - used for api calls
|
||||||
actions: {
|
actions: {
|
||||||
@ -129,7 +109,6 @@ export const store = new Vuex.Store({
|
|||||||
},
|
},
|
||||||
logout: async ({ commit, state }) => {
|
logout: async ({ commit, state }) => {
|
||||||
//console.log('action: logout')
|
//console.log('action: logout')
|
||||||
// Are we actually logged in?
|
|
||||||
if (state.session_id) {
|
if (state.session_id) {
|
||||||
const result = await loginAPI.logout(state.session_id)
|
const result = await loginAPI.logout(state.session_id)
|
||||||
// The result can be error, but thats ok with us
|
// The result can be error, but thats ok with us
|
||||||
@ -142,39 +121,11 @@ export const store = new Vuex.Store({
|
|||||||
$cookies.remove('gdd_lang')
|
$cookies.remove('gdd_lang')
|
||||||
router.push('/Login')
|
router.push('/Login')
|
||||||
},
|
},
|
||||||
ajaxCreate: async ({ dispatch, state }) => {
|
|
||||||
//console.log('action: ajaxCreate')
|
|
||||||
|
|
||||||
state.ajaxCreateData.amount = state.ajaxCreateData.amount * 10000
|
|
||||||
|
|
||||||
const result = await communityAPI.send(
|
|
||||||
state.session_id,
|
|
||||||
state.ajaxCreateData.email,
|
|
||||||
state.ajaxCreateData.amount,
|
|
||||||
state.ajaxCreateData.memo,
|
|
||||||
)
|
|
||||||
|
|
||||||
return result
|
|
||||||
//console.log(result)
|
|
||||||
},
|
|
||||||
ajaxListTransactions: async ({ commit, dispatch, state }) => {
|
|
||||||
// console.log('action: ajaxListTransactions', state.session_id)
|
|
||||||
// const result = await communityAPI.transactions(state.session_id)
|
|
||||||
},
|
|
||||||
accountBalance: async ({ commit, dispatch, state }) => {
|
accountBalance: async ({ commit, dispatch, state }) => {
|
||||||
//console.log('action: accountBalance')
|
|
||||||
// console.log('action: dispatch', dispatch)
|
|
||||||
// console.log('action: state.session_id', state.session_id)
|
|
||||||
// console.log(" action: $cookies.get('gdd_session_id') ", $cookies.get("gdd_session_id") )
|
|
||||||
// commit('session_id', $cookies.get("gdd_session_id"))
|
|
||||||
// commit('email', $cookies.get("gdd_u"))
|
|
||||||
const result = await communityAPI.balance($cookies.get('gdd_session_id'))
|
const result = await communityAPI.balance($cookies.get('gdd_session_id'))
|
||||||
//console.log("accountBalance result", result)
|
|
||||||
//console.log("aresult.result.data.balance", result.result.data.balance)
|
|
||||||
if (result.success) {
|
if (result.success) {
|
||||||
commit('user_balance', result.result.data.balance)
|
commit('user_balance', result.result.data.balance)
|
||||||
} else {
|
} else {
|
||||||
//console.log('action accountBalance to logout start')
|
|
||||||
dispatch('logout')
|
dispatch('logout')
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@ -1,169 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div>
|
|
||||||
<base-header class="pb-6 pb-8 pt-5 pt-md-8 bg-gradient-success">
|
|
||||||
<!-- Card stats -->
|
|
||||||
<b-row>
|
|
||||||
<b-col xl="3" md="6">
|
|
||||||
<stats-card
|
|
||||||
title="Total traffic"
|
|
||||||
type="gradient-red"
|
|
||||||
sub-title="350,897"
|
|
||||||
icon="ni ni-active-40"
|
|
||||||
class="mb-4"
|
|
||||||
>
|
|
||||||
<template slot="footer">
|
|
||||||
<span class="text-success mr-2">3.48%</span>
|
|
||||||
<span class="text-nowrap">Since last month</span>
|
|
||||||
</template>
|
|
||||||
</stats-card>
|
|
||||||
</b-col>
|
|
||||||
<b-col xl="3" md="6">
|
|
||||||
<stats-card
|
|
||||||
title="Total traffic"
|
|
||||||
type="gradient-orange"
|
|
||||||
sub-title="2,356"
|
|
||||||
icon="ni ni-chart-pie-35"
|
|
||||||
class="mb-4"
|
|
||||||
>
|
|
||||||
<template slot="footer">
|
|
||||||
<span class="text-success mr-2">12.18%</span>
|
|
||||||
<span class="text-nowrap">Since last month</span>
|
|
||||||
</template>
|
|
||||||
</stats-card>
|
|
||||||
</b-col>
|
|
||||||
<b-col xl="3" md="6">
|
|
||||||
<stats-card
|
|
||||||
title="Sales"
|
|
||||||
type="gradient-green"
|
|
||||||
sub-title="924"
|
|
||||||
icon="ni ni-money-coins"
|
|
||||||
class="mb-4"
|
|
||||||
>
|
|
||||||
<template slot="footer">
|
|
||||||
<span class="text-danger mr-2">5.72%</span>
|
|
||||||
<span class="text-nowrap">Since last month</span>
|
|
||||||
</template>
|
|
||||||
</stats-card>
|
|
||||||
</b-col>
|
|
||||||
<b-col xl="3" md="6">
|
|
||||||
<stats-card
|
|
||||||
title="Performance"
|
|
||||||
type="gradient-info"
|
|
||||||
sub-title="49,65%"
|
|
||||||
icon="ni ni-chart-bar-32"
|
|
||||||
class="mb-4"
|
|
||||||
>
|
|
||||||
<template slot="footer">
|
|
||||||
<span class="text-success mr-2">54.8%</span>
|
|
||||||
<span class="text-nowrap">Since last month</span>
|
|
||||||
</template>
|
|
||||||
</stats-card>
|
|
||||||
</b-col>
|
|
||||||
</b-row>
|
|
||||||
</base-header>
|
|
||||||
|
|
||||||
<b-container fluid class="mt--7">
|
|
||||||
<b-row>
|
|
||||||
<b-col>
|
|
||||||
<b-card no-body class="border-0">
|
|
||||||
<div id="map-custom" class="map-canvas" style="height: 600px"></div>
|
|
||||||
</b-card>
|
|
||||||
</b-col>
|
|
||||||
</b-row>
|
|
||||||
</b-container>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<script>
|
|
||||||
import { API_KEY } from './Maps/API_KEY'
|
|
||||||
import GoogleMapsLoader from 'google-maps'
|
|
||||||
|
|
||||||
GoogleMapsLoader.KEY = API_KEY
|
|
||||||
|
|
||||||
export default {
|
|
||||||
methods: {
|
|
||||||
initMap(google) {
|
|
||||||
let map,
|
|
||||||
lat = 40.748817,
|
|
||||||
lng = -73.985428,
|
|
||||||
color = '#5e72e4'
|
|
||||||
map = document.getElementById('map-custom')
|
|
||||||
|
|
||||||
let myLatlng = new google.maps.LatLng(lat, lng)
|
|
||||||
let mapOptions = {
|
|
||||||
zoom: 12,
|
|
||||||
scrollwheel: false,
|
|
||||||
center: myLatlng,
|
|
||||||
mapTypeId: google.maps.MapTypeId.ROADMAP,
|
|
||||||
styles: [
|
|
||||||
{
|
|
||||||
featureType: 'administrative',
|
|
||||||
elementType: 'labels.text.fill',
|
|
||||||
stylers: [{ color: '#444444' }],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
featureType: 'landscape',
|
|
||||||
elementType: 'all',
|
|
||||||
stylers: [{ color: '#f2f2f2' }],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
featureType: 'poi',
|
|
||||||
elementType: 'all',
|
|
||||||
stylers: [{ visibility: 'off' }],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
featureType: 'road',
|
|
||||||
elementType: 'all',
|
|
||||||
stylers: [{ saturation: -100 }, { lightness: 45 }],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
featureType: 'road.highway',
|
|
||||||
elementType: 'all',
|
|
||||||
stylers: [{ visibility: 'simplified' }],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
featureType: 'road.arterial',
|
|
||||||
elementType: 'labels.icon',
|
|
||||||
stylers: [{ visibility: 'off' }],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
featureType: 'transit',
|
|
||||||
elementType: 'all',
|
|
||||||
stylers: [{ visibility: 'off' }],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
featureType: 'water',
|
|
||||||
elementType: 'all',
|
|
||||||
stylers: [{ color: color }, { visibility: 'on' }],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}
|
|
||||||
|
|
||||||
map = new google.maps.Map(map, mapOptions)
|
|
||||||
|
|
||||||
let marker = new google.maps.Marker({
|
|
||||||
position: myLatlng,
|
|
||||||
map: map,
|
|
||||||
animation: google.maps.Animation.DROP,
|
|
||||||
title: 'Hello World!',
|
|
||||||
})
|
|
||||||
|
|
||||||
let contentString =
|
|
||||||
'<div class="info-window-content"><h2>Argon Dashboard PRO</h2>' +
|
|
||||||
'<p>A beautiful premium dashboard for Bootstrap 4.</p></div>'
|
|
||||||
|
|
||||||
let infowindow = new google.maps.InfoWindow({
|
|
||||||
content: contentString,
|
|
||||||
})
|
|
||||||
|
|
||||||
google.maps.event.addListener(marker, 'click', function () {
|
|
||||||
infowindow.open(map, marker)
|
|
||||||
})
|
|
||||||
},
|
|
||||||
},
|
|
||||||
mounted() {
|
|
||||||
GoogleMapsLoader.load((google) => {
|
|
||||||
this.initMap(google)
|
|
||||||
})
|
|
||||||
},
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
@ -2,25 +2,20 @@
|
|||||||
<div>
|
<div>
|
||||||
<base-header class="pb-6 pb-8 pt-5 pt-md-8 bg-transparent"></base-header>
|
<base-header class="pb-6 pb-8 pt-5 pt-md-8 bg-transparent"></base-header>
|
||||||
<b-container fluid class="mt--7">
|
<b-container fluid class="mt--7">
|
||||||
<gdd-status />
|
<gdd-status :row_form="row_form" />
|
||||||
<br />
|
<br />
|
||||||
<gdd-send />
|
<gdd-send
|
||||||
|
:row_form="row_form"
|
||||||
|
:row_check="row_check"
|
||||||
|
:row_thx="row_thx"
|
||||||
|
@change-rows="setRows"
|
||||||
|
/>
|
||||||
<hr />
|
<hr />
|
||||||
<gdd-table />
|
<gdd-table
|
||||||
<!-- <hr>
|
:row_form="row_form"
|
||||||
<div>
|
:transactions="transactions"
|
||||||
<gdd-add-work-2 />
|
@change-transactions="setTransactions"
|
||||||
</div>
|
/>
|
||||||
<br> -->
|
|
||||||
<!--
|
|
||||||
<div>
|
|
||||||
<gdd-add-work />
|
|
||||||
</div>
|
|
||||||
<br>
|
|
||||||
-->
|
|
||||||
<!-- <div>
|
|
||||||
<gdd-work-table />
|
|
||||||
</div> -->
|
|
||||||
</b-container>
|
</b-container>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@ -28,21 +23,35 @@
|
|||||||
import GddStatus from './KontoOverview/GddStatus.vue'
|
import GddStatus from './KontoOverview/GddStatus.vue'
|
||||||
import GddSend from './KontoOverview/GddSend.vue'
|
import GddSend from './KontoOverview/GddSend.vue'
|
||||||
import GddTable from './KontoOverview/GddTable.vue'
|
import GddTable from './KontoOverview/GddTable.vue'
|
||||||
// import GddAddWork2 from './KontoOverview/GddAddWork2.vue';
|
|
||||||
// import GddWorkTable from './KontoOverview/GddWorkTable.vue';
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'Overview',
|
name: 'Overview',
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
row_form: true,
|
||||||
|
row_check: false,
|
||||||
|
row_thx: false,
|
||||||
|
transactions: [],
|
||||||
|
}
|
||||||
|
},
|
||||||
components: {
|
components: {
|
||||||
GddStatus,
|
GddStatus,
|
||||||
GddSend,
|
GddSend,
|
||||||
GddTable,
|
GddTable,
|
||||||
//GddAddWork2,
|
|
||||||
//GddWorkTable
|
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
this.$store.dispatch('accountBalance', $cookies.get('gdd_session_id'))
|
this.$store.dispatch('accountBalance', $cookies.get('gdd_session_id'))
|
||||||
},
|
},
|
||||||
|
methods: {
|
||||||
|
setRows(rows) {
|
||||||
|
this.row_form = rows.row_form
|
||||||
|
this.row_check = rows.row_check
|
||||||
|
this.row_thx = rows.row_thx
|
||||||
|
},
|
||||||
|
setTransactions(transactions) {
|
||||||
|
this.transactions = transactions
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@ -8,8 +8,8 @@
|
|||||||
<b-form-input
|
<b-form-input
|
||||||
type="number"
|
type="number"
|
||||||
size="lg"
|
size="lg"
|
||||||
placeholder="0"
|
placeholder="23"
|
||||||
style="font-size: xx-large; padding-left: 20px"
|
style="font-size: xx-large; padding-left: 5px"
|
||||||
/>
|
/>
|
||||||
</base-input>
|
</base-input>
|
||||||
<base-input label="Datum / Zeitraum">
|
<base-input label="Datum / Zeitraum">
|
||||||
@ -17,7 +17,7 @@
|
|||||||
class="form-control"
|
class="form-control"
|
||||||
v-model="date"
|
v-model="date"
|
||||||
:config="config"
|
:config="config"
|
||||||
style="font-size: x-large; padding-left: 20px"
|
style="font-size: 0.5em; padding-left: 5px"
|
||||||
></flat-pickr>
|
></flat-pickr>
|
||||||
</base-input>
|
</base-input>
|
||||||
</b-col>
|
</b-col>
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<b-row v-show="$store.state.row_form">
|
<b-row v-show="row_form">
|
||||||
<b-col xl="12" md="12">
|
<b-col xl="12" md="12">
|
||||||
<b-alert variant="warning" show dismissible>
|
<b-alert variant="warning" show dismissible>
|
||||||
<strong>Achtung!</strong>
|
<strong>Achtung!</strong>
|
||||||
@ -140,28 +140,28 @@
|
|||||||
</b-card>
|
</b-card>
|
||||||
</b-col>
|
</b-col>
|
||||||
</b-row>
|
</b-row>
|
||||||
<b-row v-show="$store.state.row_check">
|
<b-row v-show="row_check">
|
||||||
<b-col>
|
<b-col>
|
||||||
<div class="display-4 p-4">Bestätige deine Zahlung. Prüfe bitte nochmal alle Daten!</div>
|
<div class="display-4 p-4">Bestätige deine Zahlung. Prüfe bitte nochmal alle Daten!</div>
|
||||||
|
|
||||||
<b-list-group>
|
<b-list-group>
|
||||||
<b-list-group-item active>Meine Zahlung</b-list-group-item>
|
<b-list-group-item active>Meine Zahlung</b-list-group-item>
|
||||||
<b-list-group-item class="d-flex justify-content-between align-items-center">
|
<b-list-group-item class="d-flex justify-content-between align-items-center">
|
||||||
{{ $store.state.ajaxCreateData.email }}
|
{{ ajaxCreateData.email }}
|
||||||
<b-badge variant="primary" pill>Empfänger</b-badge>
|
<b-badge variant="primary" pill>Empfänger</b-badge>
|
||||||
</b-list-group-item>
|
</b-list-group-item>
|
||||||
|
|
||||||
<b-list-group-item class="d-flex justify-content-between align-items-center">
|
<b-list-group-item class="d-flex justify-content-between align-items-center">
|
||||||
{{ $store.state.ajaxCreateData.amount }} GDD
|
{{ ajaxCreateData.amount }} GDD
|
||||||
<b-badge variant="primary" pill>Betrag</b-badge>
|
<b-badge variant="primary" pill>Betrag</b-badge>
|
||||||
</b-list-group-item>
|
</b-list-group-item>
|
||||||
|
|
||||||
<b-list-group-item class="d-flex justify-content-between align-items-center">
|
<b-list-group-item class="d-flex justify-content-between align-items-center">
|
||||||
{{ $store.state.ajaxCreateData.memo }}
|
{{ ajaxCreateData.memo }}
|
||||||
<b-badge variant="primary" pill>Nachricht</b-badge>
|
<b-badge variant="primary" pill>Nachricht</b-badge>
|
||||||
</b-list-group-item>
|
</b-list-group-item>
|
||||||
<b-list-group-item class="d-flex justify-content-between align-items-center">
|
<b-list-group-item class="d-flex justify-content-between align-items-center">
|
||||||
{{ $moment($store.state.ajaxCreateData.target_date).format('DD.MM.YYYY - HH:mm:ss') }}
|
{{ $moment(ajaxCreateData.target_date).format('DD.MM.YYYY - HH:mm:ss') }}
|
||||||
<b-badge variant="primary" pill>Datum</b-badge>
|
<b-badge variant="primary" pill>Datum</b-badge>
|
||||||
</b-list-group-item>
|
</b-list-group-item>
|
||||||
</b-list-group>
|
</b-list-group>
|
||||||
@ -174,7 +174,7 @@
|
|||||||
</b-row>
|
</b-row>
|
||||||
</b-col>
|
</b-col>
|
||||||
</b-row>
|
</b-row>
|
||||||
<b-row v-show="$store.state.row_thx">
|
<b-row v-show="row_thx">
|
||||||
<b-col>
|
<b-col>
|
||||||
<div class="display-1 p-4">
|
<div class="display-1 p-4">
|
||||||
Danke
|
Danke
|
||||||
@ -192,6 +192,7 @@
|
|||||||
<script>
|
<script>
|
||||||
import { QrcodeStream, QrcodeDropZone } from 'vue-qrcode-reader'
|
import { QrcodeStream, QrcodeDropZone } from 'vue-qrcode-reader'
|
||||||
import { BIcon } from 'bootstrap-vue'
|
import { BIcon } from 'bootstrap-vue'
|
||||||
|
import communityAPI from '../../apis/communityAPI.js'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'GddSent',
|
name: 'GddSent',
|
||||||
@ -200,6 +201,11 @@ export default {
|
|||||||
QrcodeDropZone,
|
QrcodeDropZone,
|
||||||
BIcon,
|
BIcon,
|
||||||
},
|
},
|
||||||
|
props: {
|
||||||
|
row_form: { type: Boolean, default: true },
|
||||||
|
row_check: { type: Boolean, default: false },
|
||||||
|
row_thx: { type: Boolean, default: false },
|
||||||
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
scan: false,
|
scan: false,
|
||||||
@ -210,48 +216,53 @@ export default {
|
|||||||
amount: '',
|
amount: '',
|
||||||
memo: '',
|
memo: '',
|
||||||
},
|
},
|
||||||
|
ajaxCreateData: {
|
||||||
|
email: '',
|
||||||
|
amount: 0,
|
||||||
|
target_date: '',
|
||||||
|
memo: '',
|
||||||
|
auto_sign: true,
|
||||||
|
},
|
||||||
send: false,
|
send: false,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {},
|
||||||
state() {
|
|
||||||
return this.name.length >= 4
|
|
||||||
},
|
|
||||||
invalidFeedback() {
|
|
||||||
if (this.name.length > 0) {
|
|
||||||
return 'Geben Sie mindestens 4 Zeichen ein.'
|
|
||||||
}
|
|
||||||
return 'Bitte geben Sie eine GDD Adresse ein.'
|
|
||||||
},
|
|
||||||
},
|
|
||||||
methods: {
|
methods: {
|
||||||
async onDecode(decodedString) {
|
async onDecode(decodedString) {
|
||||||
//console.log('onDecode JSON.parse(decodedString)', JSON.parse(decodedString))
|
|
||||||
const arr = JSON.parse(decodedString)
|
const arr = JSON.parse(decodedString)
|
||||||
//console.log('qr-email', arr[0].email)
|
|
||||||
//console.log('qr-amount', arr[0].amount)
|
|
||||||
this.form.email = arr[0].email
|
this.form.email = arr[0].email
|
||||||
this.form.amount = arr[0].amount
|
this.form.amount = arr[0].amount
|
||||||
this.scan = false
|
this.scan = false
|
||||||
},
|
},
|
||||||
async onSubmit() {
|
async onSubmit() {
|
||||||
//event.preventDefault()
|
//event.preventDefault()
|
||||||
//console.log("onSubmit", this.form)
|
this.ajaxCreateData.email = this.form.email
|
||||||
this.$store.state.ajaxCreateData.session_id = this.$cookies.get('gdd_session_id')
|
this.ajaxCreateData.amount = this.form.amount
|
||||||
this.$store.state.ajaxCreateData.email = this.form.email
|
this.ajaxCreateData.target_date = Date.now()
|
||||||
this.$store.state.ajaxCreateData.amount = this.form.amount
|
this.ajaxCreateData.memo = this.form.memo
|
||||||
this.$store.state.ajaxCreateData.memo = this.form.memo
|
|
||||||
this.$store.state.ajaxCreateData.target_date = Date.now()
|
|
||||||
|
|
||||||
this.$store.state.row_form = false
|
this.$emit('change-rows', { row_form: false, row_check: true, row_thx: false })
|
||||||
this.$store.state.row_check = true
|
|
||||||
this.$store.state.row_thx = false
|
|
||||||
},
|
},
|
||||||
sendTransaction() {
|
async sendTransaction() {
|
||||||
this.$store.dispatch('ajaxCreate')
|
this.ajaxCreateData.amount = this.ajaxCreateData.amount * 10000
|
||||||
this.$store.state.row_form = false
|
|
||||||
this.$store.state.row_check = false
|
const result = await communityAPI.send(
|
||||||
this.$store.state.row_thx = true
|
this.$store.state.session_id,
|
||||||
|
this.ajaxCreateData.email,
|
||||||
|
this.ajaxCreateData.amount,
|
||||||
|
this.ajaxCreateData.memo,
|
||||||
|
)
|
||||||
|
// console.log(result)
|
||||||
|
|
||||||
|
if (result.success) {
|
||||||
|
// console.log('send success')
|
||||||
|
|
||||||
|
this.$emit('change-rows', { row_form: false, row_check: false, row_thx: true })
|
||||||
|
} else {
|
||||||
|
// console.log('send error')
|
||||||
|
alert('error')
|
||||||
|
this.$emit('change-rows', { row_form: true, row_check: false, row_thx: false })
|
||||||
|
}
|
||||||
},
|
},
|
||||||
onReset(event) {
|
onReset(event) {
|
||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
@ -261,9 +272,7 @@ export default {
|
|||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
this.show = true
|
this.show = true
|
||||||
})
|
})
|
||||||
this.$store.state.row_form = true
|
this.$emit('change-rows', { row_form: true, row_check: false, row_thx: false })
|
||||||
this.$store.state.row_check = false
|
|
||||||
this.$store.state.row_thx = false
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<b-row v-show="$store.state.row_form">
|
<b-row v-show="this.row_form">
|
||||||
<b-col xl="6" md="6">
|
<b-col xl="6" md="6">
|
||||||
<stats-card
|
<stats-card
|
||||||
type="gradient-red"
|
type="gradient-red"
|
||||||
@ -28,5 +28,8 @@
|
|||||||
<script>
|
<script>
|
||||||
export default {
|
export default {
|
||||||
name: 'GddStatus',
|
name: 'GddStatus',
|
||||||
|
props: {
|
||||||
|
row_form: { type: Boolean, default: true },
|
||||||
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<b-list-group v-show="$store.state.row_form">
|
<b-list-group v-show="this.row_form">
|
||||||
<b-list-group-item
|
<b-list-group-item
|
||||||
v-for="item in filteredItems"
|
v-for="item in filteredItems"
|
||||||
:key="item.id"
|
:key="item.id"
|
||||||
@ -90,6 +90,9 @@ import communityAPI from '../../apis/communityAPI'
|
|||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'GddTable',
|
name: 'GddTable',
|
||||||
|
props: {
|
||||||
|
row_form: { type: Boolean, default: true },
|
||||||
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
form: [],
|
form: [],
|
||||||
|
|||||||
@ -1,178 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div>
|
|
||||||
<!-- Header -->
|
|
||||||
<div class="header bg-gradient-info py-7 py-lg-8 pt-lg-9">
|
|
||||||
<b-container>
|
|
||||||
<div class="header-body text-center mb-7">
|
|
||||||
<p class="h1">GRADIDO</p>
|
|
||||||
<p class="h4">Wallet</p>
|
|
||||||
<!-- <b-row class="justify-content-center">
|
|
||||||
<b-col xl="5" lg="6" md="6" class="px-5">
|
|
||||||
<h1 class="text-light">Landing Gradido</h1>
|
|
||||||
<br>
|
|
||||||
<router-link to="/overview" class="font-weight-bold text-white mt-5"> LoginUser</router-link>
|
|
||||||
<br><br>
|
|
||||||
<router-link to="/AdminOverview" class="font-weight-bold text-white mt-5"> Login Admin</router-link>
|
|
||||||
<br><br>
|
|
||||||
<router-link to="/register" class="font-weight-bold text-white mt-5"> Register</router-link>
|
|
||||||
</b-col>
|
|
||||||
</b-row> -->
|
|
||||||
<hr />
|
|
||||||
<p class="lead">Anmelden</p>
|
|
||||||
|
|
||||||
<b-row class="justify-content-center">
|
|
||||||
<b-col xl="5" lg="6" md="6" class="px-5">
|
|
||||||
<form @submit.prevent="login">
|
|
||||||
<b-row class="form-group">
|
|
||||||
<label
|
|
||||||
for="example-email-input"
|
|
||||||
class="col-md-2 col-form-label form-control-label"
|
|
||||||
>
|
|
||||||
Email
|
|
||||||
</label>
|
|
||||||
<b-col md="10">
|
|
||||||
<base-input
|
|
||||||
type="email"
|
|
||||||
autocomplete="username email"
|
|
||||||
placeholder="argon@example.com"
|
|
||||||
v-model="lemail"
|
|
||||||
/>
|
|
||||||
</b-col>
|
|
||||||
</b-row>
|
|
||||||
|
|
||||||
<b-row class="form-group">
|
|
||||||
<label
|
|
||||||
for="example-password-input"
|
|
||||||
class="col-md-2 col-form-label form-control-label"
|
|
||||||
>
|
|
||||||
Password
|
|
||||||
</label>
|
|
||||||
<b-col md="10">
|
|
||||||
<base-input
|
|
||||||
type="password"
|
|
||||||
autocomplete="current-password"
|
|
||||||
placeholder="password"
|
|
||||||
v-model="lpwd"
|
|
||||||
/>
|
|
||||||
</b-col>
|
|
||||||
</b-row>
|
|
||||||
|
|
||||||
<b-button block type="submit">Anmelden</b-button>
|
|
||||||
</form>
|
|
||||||
</b-col>
|
|
||||||
</b-row>
|
|
||||||
|
|
||||||
<hr />
|
|
||||||
<p class="lead">neues Mitglied anlegen</p>
|
|
||||||
|
|
||||||
<b-row class="justify-content-center">
|
|
||||||
<b-col xl="5" lg="6" md="6" class="px-5">
|
|
||||||
<form>
|
|
||||||
<b-row class="form-group">
|
|
||||||
<label class="col-md-2 col-form-label form-control-label">Vorname</label>
|
|
||||||
<b-col md="10">
|
|
||||||
<base-input placeholder="Jon " v-model="rfname"></base-input>
|
|
||||||
</b-col>
|
|
||||||
</b-row>
|
|
||||||
<b-row class="form-group">
|
|
||||||
<label class="col-md-2 col-form-label form-control-label">Nachname</label>
|
|
||||||
<b-col md="10">
|
|
||||||
<base-input placeholder=" Snow" v-model="rlname"></base-input>
|
|
||||||
</b-col>
|
|
||||||
</b-row>
|
|
||||||
<b-row class="form-group">
|
|
||||||
<label
|
|
||||||
for="example-email-input"
|
|
||||||
class="col-md-2 col-form-label form-control-label"
|
|
||||||
>
|
|
||||||
Email
|
|
||||||
</label>
|
|
||||||
<b-col md="10">
|
|
||||||
<base-input
|
|
||||||
type="email"
|
|
||||||
autocomplete="username email"
|
|
||||||
placeholder="argon@example.com"
|
|
||||||
v-model="remail"
|
|
||||||
/>
|
|
||||||
</b-col>
|
|
||||||
</b-row>
|
|
||||||
|
|
||||||
<b-row class="form-group">
|
|
||||||
<label
|
|
||||||
for="example-password-input"
|
|
||||||
class="col-md-2 col-form-label form-control-label"
|
|
||||||
>
|
|
||||||
Password
|
|
||||||
</label>
|
|
||||||
<b-col md="10">
|
|
||||||
<base-input
|
|
||||||
type="password"
|
|
||||||
autocomplete="current-password"
|
|
||||||
placeholder="password"
|
|
||||||
v-model="rpwd"
|
|
||||||
/>
|
|
||||||
</b-col>
|
|
||||||
</b-row>
|
|
||||||
</form>
|
|
||||||
<b-button block type="submit" @click="createUser()">Anmelden</b-button>
|
|
||||||
</b-col>
|
|
||||||
</b-row>
|
|
||||||
</div>
|
|
||||||
</b-container>
|
|
||||||
<div class="separator separator-bottom separator-skew zindex-100">
|
|
||||||
<svg
|
|
||||||
x="0"
|
|
||||||
y="0"
|
|
||||||
viewBox="0 0 2560 100"
|
|
||||||
preserveAspectRatio="none"
|
|
||||||
version="1.1"
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
>
|
|
||||||
<polygon class="fill-default" points="2560 0 2560 100 0 100"></polygon>
|
|
||||||
</svg>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<!-- Page content -->
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<script>
|
|
||||||
// Components
|
|
||||||
|
|
||||||
export default {
|
|
||||||
name: 'Landing',
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
lemail: '',
|
|
||||||
lpwd: '',
|
|
||||||
rfname: '',
|
|
||||||
rlname: '',
|
|
||||||
remail: '',
|
|
||||||
rpwd: '',
|
|
||||||
}
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
login() {
|
|
||||||
//if (this.lemail !== '' || this.lpwd !== '') { // TODO this should be done via form validation
|
|
||||||
this.$store.dispatch('login', {
|
|
||||||
email: this.lemail,
|
|
||||||
password: this.lpwd,
|
|
||||||
})
|
|
||||||
//}
|
|
||||||
},
|
|
||||||
createUser() {
|
|
||||||
this.$store.dispatch('createUser', {
|
|
||||||
email: this.remail,
|
|
||||||
first_name: this.rfname,
|
|
||||||
last_name: this.rlname,
|
|
||||||
password: this.rpwd,
|
|
||||||
})
|
|
||||||
},
|
|
||||||
loginAsAdmin() {
|
|
||||||
//console.log('app.vue admin login(): ' + this.$store.state.is_admin)
|
|
||||||
this.modals = false
|
|
||||||
this.$store.commit('loginAsAdmin')
|
|
||||||
this.$router.push('/AdminOverview')
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
@ -3,12 +3,7 @@
|
|||||||
<!-- Header -->
|
<!-- Header -->
|
||||||
<div class="header bg-gradient-info py-7 py-lg-8 pt-lg-9">
|
<div class="header bg-gradient-info py-7 py-lg-8 pt-lg-9">
|
||||||
<b-container>
|
<b-container>
|
||||||
<div class="header-body text-center mb-7">
|
<div class="header-body text-center mb-3">
|
||||||
<b-row class="justify-content-center">
|
|
||||||
<b-col xl="5" lg="6" md="6" class="px-5">
|
|
||||||
<h1 class="text-light">{{ $t('site.404.text') }}</h1>
|
|
||||||
</b-col>
|
|
||||||
</b-row>
|
|
||||||
<a href="/login" to="/login">
|
<a href="/login" to="/login">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
@ -1189,38 +1184,7 @@
|
|||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</b-container>
|
</b-container>
|
||||||
<div class="separator separator-bottom separator-skew zindex-100">
|
|
||||||
<svg
|
|
||||||
x="0"
|
|
||||||
y="0"
|
|
||||||
viewBox="0 0 2560 100"
|
|
||||||
preserveAspectRatio="none"
|
|
||||||
version="1.1"
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
>
|
|
||||||
<polygon class="fill-default" points="2560 0 2560 100 0 100"></polygon>
|
|
||||||
</svg>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<!-- Page content -->
|
|
||||||
<section class="py-6">
|
|
||||||
<b-container>
|
|
||||||
<b-row align-v="center" class="row-grid">
|
|
||||||
<b-col md="6">
|
|
||||||
<b-img src="img/theme/landing-1.png" fluid />
|
|
||||||
</b-col>
|
|
||||||
<b-col md="6">
|
|
||||||
<div class="pr-md-5">
|
|
||||||
<h1 class="text-light">{{ $t('site.landing1.explore') }}</h1>
|
|
||||||
<p class="text-light">{{ $t('site.landing1.text') }}</p>
|
|
||||||
<router-link to="/overview" class="font-weight-bold text-warning mt-5">
|
|
||||||
{{ $t('site.landing1.link') }}
|
|
||||||
</router-link>
|
|
||||||
</div>
|
|
||||||
</b-col>
|
|
||||||
</b-row>
|
|
||||||
</b-container>
|
|
||||||
</section>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|||||||
@ -1,115 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div>
|
|
||||||
<base-header class="pb-6 pb-8 pt-5 pt-md-8 bg-gradient-success">
|
|
||||||
<!-- Card stats -->
|
|
||||||
<b-row>
|
|
||||||
<b-col xl="3" md="6">
|
|
||||||
<stats-card
|
|
||||||
title="Total traffic"
|
|
||||||
type="gradient-red"
|
|
||||||
sub-title="350,897"
|
|
||||||
icon="ni ni-active-40"
|
|
||||||
class="mb-4"
|
|
||||||
>
|
|
||||||
<template slot="footer">
|
|
||||||
<span class="text-success mr-2">3.48%</span>
|
|
||||||
<span class="text-nowrap">Since last month</span>
|
|
||||||
</template>
|
|
||||||
</stats-card>
|
|
||||||
</b-col>
|
|
||||||
<b-col xl="3" md="6">
|
|
||||||
<stats-card
|
|
||||||
title="Total traffic"
|
|
||||||
type="gradient-orange"
|
|
||||||
sub-title="2,356"
|
|
||||||
icon="ni ni-chart-pie-35"
|
|
||||||
class="mb-4"
|
|
||||||
>
|
|
||||||
<template slot="footer">
|
|
||||||
<span class="text-success mr-2">12.18%</span>
|
|
||||||
<span class="text-nowrap">Since last month</span>
|
|
||||||
</template>
|
|
||||||
</stats-card>
|
|
||||||
</b-col>
|
|
||||||
<b-col xl="3" md="6">
|
|
||||||
<stats-card
|
|
||||||
title="Sales"
|
|
||||||
type="gradient-green"
|
|
||||||
sub-title="924"
|
|
||||||
icon="ni ni-money-coins"
|
|
||||||
class="mb-4"
|
|
||||||
>
|
|
||||||
<template slot="footer">
|
|
||||||
<span class="text-danger mr-2">5.72%</span>
|
|
||||||
<span class="text-nowrap">Since last month</span>
|
|
||||||
</template>
|
|
||||||
</stats-card>
|
|
||||||
</b-col>
|
|
||||||
<b-col xl="3" md="6">
|
|
||||||
<stats-card
|
|
||||||
title="Performance"
|
|
||||||
type="gradient-info"
|
|
||||||
sub-title="49,65%"
|
|
||||||
icon="ni ni-chart-bar-32"
|
|
||||||
class="mb-4"
|
|
||||||
>
|
|
||||||
<template slot="footer">
|
|
||||||
<span class="text-success mr-2">54.8%</span>
|
|
||||||
<span class="text-nowrap">Since last month</span>
|
|
||||||
</template>
|
|
||||||
</stats-card>
|
|
||||||
</b-col>
|
|
||||||
</b-row>
|
|
||||||
</base-header>
|
|
||||||
<b-container fluid class="mt--7">
|
|
||||||
<b-row>
|
|
||||||
<b-col>
|
|
||||||
<light-table />
|
|
||||||
</b-col>
|
|
||||||
</b-row>
|
|
||||||
<div class="mt-5"></div>
|
|
||||||
<dark-table></dark-table>
|
|
||||||
</b-container>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<script>
|
|
||||||
import { Dropdown, DropdownItem, DropdownMenu, Table, TableColumn } from 'element-ui'
|
|
||||||
import projects from './Tables/projects'
|
|
||||||
import users from './Tables/users'
|
|
||||||
import LightTable from './Tables/RegularTables/LightTable'
|
|
||||||
import DarkTable from './Tables/RegularTables/DarkTable'
|
|
||||||
|
|
||||||
export default {
|
|
||||||
components: {
|
|
||||||
LightTable,
|
|
||||||
DarkTable,
|
|
||||||
[Dropdown.name]: Dropdown,
|
|
||||||
[DropdownItem.name]: DropdownItem,
|
|
||||||
[DropdownMenu.name]: DropdownMenu,
|
|
||||||
[Table.name]: Table,
|
|
||||||
[TableColumn.name]: TableColumn,
|
|
||||||
},
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
projects,
|
|
||||||
users,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
<style>
|
|
||||||
.el-table.table-dark {
|
|
||||||
background-color: #172b4d;
|
|
||||||
color: #f8f9fe;
|
|
||||||
}
|
|
||||||
|
|
||||||
.el-table.table-dark th,
|
|
||||||
.el-table.table-dark tr {
|
|
||||||
background-color: #172b4d;
|
|
||||||
}
|
|
||||||
|
|
||||||
.el-table.table-dark td,
|
|
||||||
.el-table.table-dark th.is-leaf {
|
|
||||||
border-bottom: none;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
Loading…
x
Reference in New Issue
Block a user