mirror of
https://github.com/IT4Change/gradido.git
synced 2025-12-13 07:45:54 +00:00
Merge branch 'master' into 2370-feature-deleting-contribution-must-be-analog-to-confirming-contribution-dialog
This commit is contained in:
commit
579ef7b25e
3
.github/workflows/test.yml
vendored
3
.github/workflows/test.yml
vendored
@ -35,7 +35,6 @@ jobs:
|
|||||||
build_test_admin:
|
build_test_admin:
|
||||||
name: Docker Build Test - Admin Interface
|
name: Docker Build Test - Admin Interface
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
#needs: [nothing]
|
|
||||||
steps:
|
steps:
|
||||||
##########################################################################
|
##########################################################################
|
||||||
# CHECKOUT CODE ##########################################################
|
# CHECKOUT CODE ##########################################################
|
||||||
@ -437,7 +436,7 @@ jobs:
|
|||||||
report_name: Coverage Frontend
|
report_name: Coverage Frontend
|
||||||
type: lcov
|
type: lcov
|
||||||
result_path: ./coverage/lcov.info
|
result_path: ./coverage/lcov.info
|
||||||
min_coverage: 91
|
min_coverage: 93
|
||||||
token: ${{ github.token }}
|
token: ${{ github.token }}
|
||||||
|
|
||||||
##############################################################################
|
##############################################################################
|
||||||
|
|||||||
68
CHANGELOG.md
68
CHANGELOG.md
@ -4,8 +4,76 @@ All notable changes to this project will be documented in this file. Dates are d
|
|||||||
|
|
||||||
Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
|
Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
|
||||||
|
|
||||||
|
#### [1.17.1](https://github.com/gradido/gradido/compare/1.17.0...1.17.1)
|
||||||
|
|
||||||
|
- refactor(frontend): change contribution memo add word-break [`#2583`](https://github.com/gradido/gradido/pull/2583)
|
||||||
|
- refactor(admin): add text-break on all table memo fields [`#2584`](https://github.com/gradido/gradido/pull/2584)
|
||||||
|
- fix(frontend): throw proper frontend warning errors [`#2586`](https://github.com/gradido/gradido/pull/2586)
|
||||||
|
- refactor(frontend): equalize en with fr languages. [`#2585`](https://github.com/gradido/gradido/pull/2585)
|
||||||
|
- refactor(frontend): forgot password unit tests [`#2582`](https://github.com/gradido/gradido/pull/2582)
|
||||||
|
- fix(frontend): fix min value for hours input [`#2581`](https://github.com/gradido/gradido/pull/2581)
|
||||||
|
- fix(frontend): change dropdown placement calender no-flip true [`#2580`](https://github.com/gradido/gradido/pull/2580)
|
||||||
|
- refactor(frontend): link send result style [`#2577`](https://github.com/gradido/gradido/pull/2577)
|
||||||
|
- refactor(frontend): remove vertical scrolling & small fixes [`#2578`](https://github.com/gradido/gradido/pull/2578)
|
||||||
|
- refactor(frontend): tyle mobile device auth template [`#2576`](https://github.com/gradido/gradido/pull/2576)
|
||||||
|
|
||||||
|
#### [1.17.0](https://github.com/gradido/gradido/compare/1.16.0...1.17.0)
|
||||||
|
|
||||||
|
> 18 January 2023
|
||||||
|
|
||||||
|
- chore(release): v1.17.0 [`#2575`](https://github.com/gradido/gradido/pull/2575)
|
||||||
|
- fix(frontend): submit contribution text [`#2573`](https://github.com/gradido/gradido/pull/2573)
|
||||||
|
- fix(backend): admin cannot delete confirmed contribution [`#2571`](https://github.com/gradido/gradido/pull/2571)
|
||||||
|
- fix(frontend): english locales - horas -> hours [`#2572`](https://github.com/gradido/gradido/pull/2572)
|
||||||
|
- fix(frontend): mobil divices datepicker add props dropleft [`#2570`](https://github.com/gradido/gradido/pull/2570)
|
||||||
|
- fix(frontend): pagination [`#2569`](https://github.com/gradido/gradido/pull/2569)
|
||||||
|
- fix(frontend): add a watch on gdt prop to assure propper loading when mounted [`#2568`](https://github.com/gradido/gradido/pull/2568)
|
||||||
|
- refactor(frontend): creation step in quarter hour set [`#2566`](https://github.com/gradido/gradido/pull/2566)
|
||||||
|
- fix(frontend): tunneled email on right side last transactions [`#2561`](https://github.com/gradido/gradido/pull/2561)
|
||||||
|
- feat(frontend): test transaction page [`#2555`](https://github.com/gradido/gradido/pull/2555)
|
||||||
|
- refactor(backend): statistics with field resolvers [`#2553`](https://github.com/gradido/gradido/pull/2553)
|
||||||
|
- fix(frontend): normalized amount transaction if processed again [`#2550`](https://github.com/gradido/gradido/pull/2550)
|
||||||
|
- fix(backend): semaphore deadlock [`#2551`](https://github.com/gradido/gradido/pull/2551)
|
||||||
|
- fix(frontend): mobile design [`#2552`](https://github.com/gradido/gradido/pull/2552)
|
||||||
|
- refactor(frontend): slots for right sidebar and header [`#2548`](https://github.com/gradido/gradido/pull/2548)
|
||||||
|
- fix(frontend): creation menu highlighted on all submenus [`#2527`](https://github.com/gradido/gradido/pull/2527)
|
||||||
|
- refactor(frontend): computed hours for open creations [`#2545`](https://github.com/gradido/gradido/pull/2545)
|
||||||
|
- feat(other): add description for daily backup cronjob [`#2532`](https://github.com/gradido/gradido/pull/2532)
|
||||||
|
- fix(frontend): editing transaction does not work [`#2543`](https://github.com/gradido/gradido/pull/2543)
|
||||||
|
- refactor(frontend): remove open creations from store [`#2541`](https://github.com/gradido/gradido/pull/2541)
|
||||||
|
- feat(other): vscode extensions [`#2524`](https://github.com/gradido/gradido/pull/2524)
|
||||||
|
- fix(backend): remove jest from dependecies [`#2533`](https://github.com/gradido/gradido/pull/2533)
|
||||||
|
- fix(frontend): initials without space [`#2546`](https://github.com/gradido/gradido/pull/2546)
|
||||||
|
- fix(backend): fix backend not confirmable [`#2539`](https://github.com/gradido/gradido/pull/2539)
|
||||||
|
- fix(frontend): send gdd and send link gdd is running [`#2534`](https://github.com/gradido/gradido/pull/2534)
|
||||||
|
- fix(other): update browser list [`#2540`](https://github.com/gradido/gradido/pull/2540)
|
||||||
|
- test(backend): increase backend coverage to 78% [`#2542`](https://github.com/gradido/gradido/pull/2542)
|
||||||
|
- fix(frontend): pagination gdt [`#2525`](https://github.com/gradido/gradido/pull/2525)
|
||||||
|
- fix(frontend): leaves are over the user symbol [`#2526`](https://github.com/gradido/gradido/pull/2526)
|
||||||
|
- fix(frontend): input-email label and placeholder are displayed correctly per language [`#2528`](https://github.com/gradido/gradido/pull/2528)
|
||||||
|
- feat(backend): add hideAmountGDD & hideAmountGDT to users table. [`#2506`](https://github.com/gradido/gradido/pull/2506)
|
||||||
|
- fix(frontend): avatar initials always has 2 letters [`#2530`](https://github.com/gradido/gradido/pull/2530)
|
||||||
|
- refactor(backend): seed contributions as user [`#2460`](https://github.com/gradido/gradido/pull/2460)
|
||||||
|
- fix(backend): fix logger middleware [`#2503`](https://github.com/gradido/gradido/pull/2503)
|
||||||
|
- fix(backend): fix email text [`#2523`](https://github.com/gradido/gradido/pull/2523)
|
||||||
|
- feat(other): new scopes for lint pr [`#2489`](https://github.com/gradido/gradido/pull/2489)
|
||||||
|
- fix(backend): fix config - some typos [`#2477`](https://github.com/gradido/gradido/pull/2477)
|
||||||
|
- style(frontend): new Design [`#2297`](https://github.com/gradido/gradido/pull/2297)
|
||||||
|
- refactor(other): adjust some texts and translations [`#2504`](https://github.com/gradido/gradido/pull/2504)
|
||||||
|
- test(other): fix tests breaking with the new year [`#2505`](https://github.com/gradido/gradido/pull/2505)
|
||||||
|
- feat(backend): federation implement exchange of api versions persist in table [`#2427`](https://github.com/gradido/gradido/pull/2427)
|
||||||
|
- feat(backend): semaphore to lock transaction table [`#2458`](https://github.com/gradido/gradido/pull/2458)
|
||||||
|
- feat(backend): design html emails and adjust texts [`#2472`](https://github.com/gradido/gradido/pull/2472)
|
||||||
|
- feat(backend): test semaphore [`#2468`](https://github.com/gradido/gradido/pull/2468)
|
||||||
|
- fix(admin): reduce triggers of success toast on deleted user form to exactly one [`#2471`](https://github.com/gradido/gradido/pull/2471)
|
||||||
|
- refactor(other): build nginx docker image in workflow independent of other builds [`#2470`](https://github.com/gradido/gradido/pull/2470)
|
||||||
|
- feat(backend): setup unit tests for federation [`#2465`](https://github.com/gradido/gradido/pull/2465)
|
||||||
|
|
||||||
#### [1.16.0](https://github.com/gradido/gradido/compare/1.15.0...1.16.0)
|
#### [1.16.0](https://github.com/gradido/gradido/compare/1.15.0...1.16.0)
|
||||||
|
|
||||||
|
> 15 December 2022
|
||||||
|
|
||||||
|
- feat(release): version 1.16.0 [`#2467`](https://github.com/gradido/gradido/pull/2467)
|
||||||
- refactor(backend): cleaning user related old password junk [`#2426`](https://github.com/gradido/gradido/pull/2426)
|
- refactor(backend): cleaning user related old password junk [`#2426`](https://github.com/gradido/gradido/pull/2426)
|
||||||
- fix(database): consistent transaction table [`#2453`](https://github.com/gradido/gradido/pull/2453)
|
- fix(database): consistent transaction table [`#2453`](https://github.com/gradido/gradido/pull/2453)
|
||||||
- refactor(backend): dissolve admin resolver [`#2416`](https://github.com/gradido/gradido/pull/2416)
|
- refactor(backend): dissolve admin resolver [`#2416`](https://github.com/gradido/gradido/pull/2416)
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
"description": "Administraion Interface for Gradido",
|
"description": "Administraion Interface for Gradido",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"author": "Moriz Wahl",
|
"author": "Moriz Wahl",
|
||||||
"version": "1.16.0",
|
"version": "1.17.1",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"private": false,
|
"private": false,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
@ -88,7 +88,7 @@ export default {
|
|||||||
return `${value} GDD`
|
return `${value} GDD`
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{ key: 'memo', label: this.$t('transactionlist.memo') },
|
{ key: 'memo', label: this.$t('transactionlist.memo'), class: 'text-break' },
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@ -57,7 +57,7 @@ const propsData = {
|
|||||||
return value + ' GDD'
|
return value + ' GDD'
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{ key: 'memo', label: 'text' },
|
{ key: 'memo', label: 'text', class: 'text-break' },
|
||||||
{
|
{
|
||||||
key: 'date',
|
key: 'date',
|
||||||
label: 'date',
|
label: 'date',
|
||||||
|
|||||||
@ -67,7 +67,7 @@ export default {
|
|||||||
return `${value} GDD`
|
return `${value} GDD`
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{ key: 'memo', label: this.$t('transactionlist.memo') },
|
{ key: 'memo', label: this.$t('transactionlist.memo'), class: 'text-break' },
|
||||||
{
|
{
|
||||||
key: 'validUntil',
|
key: 'validUntil',
|
||||||
label: this.$t('transactionlink.valid_until'),
|
label: this.$t('transactionlink.valid_until'),
|
||||||
|
|||||||
@ -4,12 +4,14 @@ export const communityStatistics = gql`
|
|||||||
query {
|
query {
|
||||||
communityStatistics {
|
communityStatistics {
|
||||||
totalUsers
|
totalUsers
|
||||||
activeUsers
|
|
||||||
deletedUsers
|
deletedUsers
|
||||||
totalGradidoCreated
|
totalGradidoCreated
|
||||||
totalGradidoDecayed
|
totalGradidoDecayed
|
||||||
totalGradidoAvailable
|
dynamicStatisticsFields {
|
||||||
totalGradidoUnbookedDecayed
|
activeUsers
|
||||||
|
totalGradidoAvailable
|
||||||
|
totalGradidoUnbookedDecayed
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|||||||
@ -17,12 +17,14 @@ const defaultData = () => {
|
|||||||
return {
|
return {
|
||||||
communityStatistics: {
|
communityStatistics: {
|
||||||
totalUsers: 3113,
|
totalUsers: 3113,
|
||||||
activeUsers: 1057,
|
|
||||||
deletedUsers: 35,
|
deletedUsers: 35,
|
||||||
totalGradidoCreated: '4083774.05000000000000000000',
|
totalGradidoCreated: '4083774.05000000000000000000',
|
||||||
totalGradidoDecayed: '-1062639.13634129622923372197',
|
totalGradidoDecayed: '-1062639.13634129622923372197',
|
||||||
totalGradidoAvailable: '2513565.869444365732411569',
|
dynamicStatisticsFields: {
|
||||||
totalGradidoUnbookedDecayed: '-500474.6738366222166261272',
|
activeUsers: 1057,
|
||||||
|
totalGradidoAvailable: '2513565.869444365732411569',
|
||||||
|
totalGradidoUnbookedDecayed: '-500474.6738366222166261272',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -31,7 +31,9 @@ export default {
|
|||||||
return communityStatistics
|
return communityStatistics
|
||||||
},
|
},
|
||||||
update({ communityStatistics }) {
|
update({ communityStatistics }) {
|
||||||
this.statistics = communityStatistics
|
const totals = { ...communityStatistics.dynamicStatisticsFields }
|
||||||
|
this.statistics = { ...communityStatistics, ...totals }
|
||||||
|
delete this.statistics.dynamicStatisticsFields
|
||||||
},
|
},
|
||||||
error({ message }) {
|
error({ message }) {
|
||||||
this.toastError(message)
|
this.toastError(message)
|
||||||
|
|||||||
@ -142,7 +142,7 @@ export default {
|
|||||||
return value + ' GDD'
|
return value + ' GDD'
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{ key: 'memo', label: this.$t('text') },
|
{ key: 'memo', label: this.$t('text'), class: 'text-break' },
|
||||||
{
|
{
|
||||||
key: 'date',
|
key: 'date',
|
||||||
label: this.$t('date'),
|
label: this.$t('date'),
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "gradido-backend",
|
"name": "gradido-backend",
|
||||||
"version": "1.16.0",
|
"version": "1.17.1",
|
||||||
"description": "Gradido unified backend providing an API-Service for Gradido Transactions",
|
"description": "Gradido unified backend providing an API-Service for Gradido Transactions",
|
||||||
"main": "src/index.ts",
|
"main": "src/index.ts",
|
||||||
"repository": "https://github.com/gradido/gradido/backend",
|
"repository": "https://github.com/gradido/gradido/backend",
|
||||||
|
|||||||
@ -2,13 +2,25 @@ import { ObjectType, Field } from 'type-graphql'
|
|||||||
import Decimal from 'decimal.js-light'
|
import Decimal from 'decimal.js-light'
|
||||||
|
|
||||||
@ObjectType()
|
@ObjectType()
|
||||||
export class CommunityStatistics {
|
export class DynamicStatisticsFields {
|
||||||
@Field(() => Number)
|
|
||||||
totalUsers: number
|
|
||||||
|
|
||||||
@Field(() => Number)
|
@Field(() => Number)
|
||||||
activeUsers: number
|
activeUsers: number
|
||||||
|
|
||||||
|
@Field(() => Decimal)
|
||||||
|
totalGradidoAvailable: Decimal
|
||||||
|
|
||||||
|
@Field(() => Decimal)
|
||||||
|
totalGradidoUnbookedDecayed: Decimal
|
||||||
|
}
|
||||||
|
|
||||||
|
@ObjectType()
|
||||||
|
export class CommunityStatistics {
|
||||||
|
@Field(() => Number)
|
||||||
|
allUsers: number
|
||||||
|
|
||||||
|
@Field(() => Number)
|
||||||
|
totalUsers: number
|
||||||
|
|
||||||
@Field(() => Number)
|
@Field(() => Number)
|
||||||
deletedUsers: number
|
deletedUsers: number
|
||||||
|
|
||||||
@ -18,9 +30,7 @@ export class CommunityStatistics {
|
|||||||
@Field(() => Decimal)
|
@Field(() => Decimal)
|
||||||
totalGradidoDecayed: Decimal
|
totalGradidoDecayed: Decimal
|
||||||
|
|
||||||
@Field(() => Decimal)
|
// be carefull querying this, takes longer than 2 secs.
|
||||||
totalGradidoAvailable: Decimal
|
@Field(() => DynamicStatisticsFields)
|
||||||
|
dynamicStatisticsFields: DynamicStatisticsFields
|
||||||
@Field(() => Decimal)
|
|
||||||
totalGradidoUnbookedDecayed: Decimal
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
import Decimal from 'decimal.js-light'
|
import Decimal from 'decimal.js-light'
|
||||||
import { bibiBloxberg } from '@/seeds/users/bibi-bloxberg'
|
import { bibiBloxberg } from '@/seeds/users/bibi-bloxberg'
|
||||||
|
import { bobBaumeister } from '@/seeds/users/bob-baumeister'
|
||||||
import { stephenHawking } from '@/seeds/users/stephen-hawking'
|
import { stephenHawking } from '@/seeds/users/stephen-hawking'
|
||||||
import { garrickOllivander } from '@/seeds/users/garrick-ollivander'
|
import { garrickOllivander } from '@/seeds/users/garrick-ollivander'
|
||||||
import {
|
import {
|
||||||
@ -26,7 +27,13 @@ import {
|
|||||||
sendContributionConfirmedEmail,
|
sendContributionConfirmedEmail,
|
||||||
// sendContributionRejectedEmail,
|
// sendContributionRejectedEmail,
|
||||||
} from '@/emails/sendEmailVariants'
|
} from '@/emails/sendEmailVariants'
|
||||||
import { cleanDB, resetToken, testEnvironment, contributionDateFormatter } from '@test/helpers'
|
import {
|
||||||
|
cleanDB,
|
||||||
|
resetToken,
|
||||||
|
testEnvironment,
|
||||||
|
contributionDateFormatter,
|
||||||
|
resetEntity,
|
||||||
|
} from '@test/helpers'
|
||||||
import { GraphQLError } from 'graphql'
|
import { GraphQLError } from 'graphql'
|
||||||
import { userFactory } from '@/seeds/factory/user'
|
import { userFactory } from '@/seeds/factory/user'
|
||||||
import { creationFactory } from '@/seeds/factory/creation'
|
import { creationFactory } from '@/seeds/factory/creation'
|
||||||
@ -1818,6 +1825,49 @@ describe('ContributionResolver', () => {
|
|||||||
)
|
)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('creation already confirmed', () => {
|
||||||
|
it('throws an error', async () => {
|
||||||
|
await userFactory(testEnv, bobBaumeister)
|
||||||
|
await query({
|
||||||
|
query: login,
|
||||||
|
variables: { email: 'bob@baumeister.de', password: 'Aa12345_' },
|
||||||
|
})
|
||||||
|
const {
|
||||||
|
data: { createContribution: confirmedContribution },
|
||||||
|
} = await mutate({
|
||||||
|
mutation: createContribution,
|
||||||
|
variables: {
|
||||||
|
amount: 100.0,
|
||||||
|
memo: 'Confirmed Contribution',
|
||||||
|
creationDate: contributionDateFormatter(new Date()),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
await query({
|
||||||
|
query: login,
|
||||||
|
variables: { email: 'peter@lustig.de', password: 'Aa12345_' },
|
||||||
|
})
|
||||||
|
await mutate({
|
||||||
|
mutation: confirmContribution,
|
||||||
|
variables: {
|
||||||
|
id: confirmedContribution.id ? confirmedContribution.id : -1,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
await expect(
|
||||||
|
mutate({
|
||||||
|
mutation: adminDeleteContribution,
|
||||||
|
variables: {
|
||||||
|
id: confirmedContribution.id ? confirmedContribution.id : -1,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
).resolves.toEqual(
|
||||||
|
expect.objectContaining({
|
||||||
|
errors: [new GraphQLError('A confirmed contribution can not be deleted')],
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
await resetEntity(DbTransaction)
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('confirmContribution', () => {
|
describe('confirmContribution', () => {
|
||||||
|
|||||||
@ -512,6 +512,10 @@ export class ContributionResolver {
|
|||||||
logger.error(`Contribution not found for given id: ${id}`)
|
logger.error(`Contribution not found for given id: ${id}`)
|
||||||
throw new Error('Contribution not found for given id.')
|
throw new Error('Contribution not found for given id.')
|
||||||
}
|
}
|
||||||
|
if (contribution.confirmedAt) {
|
||||||
|
logger.error('A confirmed contribution can not be deleted')
|
||||||
|
throw new Error('A confirmed contribution can not be deleted')
|
||||||
|
}
|
||||||
const moderator = getUser(context)
|
const moderator = getUser(context)
|
||||||
if (
|
if (
|
||||||
contribution.contributionType === ContributionType.USER &&
|
contribution.contributionType === ContributionType.USER &&
|
||||||
@ -557,7 +561,6 @@ export class ContributionResolver {
|
|||||||
): Promise<boolean> {
|
): Promise<boolean> {
|
||||||
// acquire lock
|
// acquire lock
|
||||||
const releaseLock = await TRANSACTIONS_LOCK.acquire()
|
const releaseLock = await TRANSACTIONS_LOCK.acquire()
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const clientTimezoneOffset = getClientTimezoneOffset(context)
|
const clientTimezoneOffset = getClientTimezoneOffset(context)
|
||||||
const contribution = await DbContribution.findOne(id)
|
const contribution = await DbContribution.findOne(id)
|
||||||
@ -664,7 +667,6 @@ export class ContributionResolver {
|
|||||||
} finally {
|
} finally {
|
||||||
releaseLock()
|
releaseLock()
|
||||||
}
|
}
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,81 +1,113 @@
|
|||||||
import Decimal from 'decimal.js-light'
|
import Decimal from 'decimal.js-light'
|
||||||
import { Resolver, Query, Authorized } from 'type-graphql'
|
import { Resolver, Query, Authorized, FieldResolver } from 'type-graphql'
|
||||||
import { getConnection } from '@dbTools/typeorm'
|
import { getConnection } from '@dbTools/typeorm'
|
||||||
|
|
||||||
import { Transaction as DbTransaction } from '@entity/Transaction'
|
import { Transaction as DbTransaction } from '@entity/Transaction'
|
||||||
import { User as DbUser } from '@entity/User'
|
import { User as DbUser } from '@entity/User'
|
||||||
|
|
||||||
import { CommunityStatistics } from '@model/CommunityStatistics'
|
import { CommunityStatistics, DynamicStatisticsFields } from '@model/CommunityStatistics'
|
||||||
|
|
||||||
import { RIGHTS } from '@/auth/RIGHTS'
|
import { RIGHTS } from '@/auth/RIGHTS'
|
||||||
import { calculateDecay } from '@/util/decay'
|
import { calculateDecay } from '@/util/decay'
|
||||||
|
|
||||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
/* eslint-disable-next-line @typescript-eslint/no-unused-vars */
|
||||||
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
@Resolver((of) => CommunityStatistics)
|
||||||
|
|
||||||
@Resolver()
|
|
||||||
export class StatisticsResolver {
|
export class StatisticsResolver {
|
||||||
@Authorized([RIGHTS.COMMUNITY_STATISTICS])
|
@Authorized([RIGHTS.COMMUNITY_STATISTICS])
|
||||||
@Query(() => CommunityStatistics)
|
@Query(() => CommunityStatistics)
|
||||||
async communityStatistics(): Promise<CommunityStatistics> {
|
async communityStatistics(): Promise<CommunityStatistics> {
|
||||||
const allUsers = await DbUser.count({ withDeleted: true })
|
return new CommunityStatistics()
|
||||||
const totalUsers = await DbUser.count()
|
}
|
||||||
const deletedUsers = allUsers - totalUsers
|
|
||||||
|
|
||||||
|
@FieldResolver(() => Decimal)
|
||||||
|
async allUsers(): Promise<number> {
|
||||||
|
return await DbUser.count({ withDeleted: true })
|
||||||
|
}
|
||||||
|
|
||||||
|
@FieldResolver()
|
||||||
|
async totalUsers(): Promise<number> {
|
||||||
|
return await DbUser.count()
|
||||||
|
}
|
||||||
|
|
||||||
|
@FieldResolver()
|
||||||
|
async deletedUsers(): Promise<number> {
|
||||||
|
return (await this.allUsers()) - (await this.totalUsers())
|
||||||
|
}
|
||||||
|
|
||||||
|
@FieldResolver()
|
||||||
|
async totalGradidoCreated(): Promise<Decimal> {
|
||||||
|
const queryRunner = getConnection().createQueryRunner()
|
||||||
|
try {
|
||||||
|
await queryRunner.connect()
|
||||||
|
const { totalGradidoCreated } = await queryRunner.manager
|
||||||
|
.createQueryBuilder()
|
||||||
|
.select('SUM(transaction.amount) AS totalGradidoCreated')
|
||||||
|
.from(DbTransaction, 'transaction')
|
||||||
|
.where('transaction.typeId = 1')
|
||||||
|
.getRawOne()
|
||||||
|
return totalGradidoCreated
|
||||||
|
} finally {
|
||||||
|
await queryRunner.release()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@FieldResolver()
|
||||||
|
async totalGradidoDecayed(): Promise<Decimal> {
|
||||||
|
const queryRunner = getConnection().createQueryRunner()
|
||||||
|
try {
|
||||||
|
await queryRunner.connect()
|
||||||
|
const { totalGradidoDecayed } = await queryRunner.manager
|
||||||
|
.createQueryBuilder()
|
||||||
|
.select('SUM(transaction.decay) AS totalGradidoDecayed')
|
||||||
|
.from(DbTransaction, 'transaction')
|
||||||
|
.where('transaction.decay IS NOT NULL')
|
||||||
|
.getRawOne()
|
||||||
|
return totalGradidoDecayed
|
||||||
|
} finally {
|
||||||
|
await queryRunner.release()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@FieldResolver()
|
||||||
|
async dynamicStatisticsFields(): Promise<DynamicStatisticsFields> {
|
||||||
let totalGradidoAvailable: Decimal = new Decimal(0)
|
let totalGradidoAvailable: Decimal = new Decimal(0)
|
||||||
let totalGradidoUnbookedDecayed: Decimal = new Decimal(0)
|
let totalGradidoUnbookedDecayed: Decimal = new Decimal(0)
|
||||||
|
|
||||||
const receivedCallDate = new Date()
|
const receivedCallDate = new Date()
|
||||||
|
|
||||||
const queryRunner = getConnection().createQueryRunner()
|
const queryRunner = getConnection().createQueryRunner()
|
||||||
await queryRunner.connect()
|
try {
|
||||||
|
await queryRunner.connect()
|
||||||
|
|
||||||
const lastUserTransactions = await queryRunner.manager
|
const lastUserTransactions = await queryRunner.manager
|
||||||
.createQueryBuilder(DbUser, 'user')
|
.createQueryBuilder(DbUser, 'user')
|
||||||
.select('transaction.balance', 'balance')
|
.select('transaction.balance', 'balance')
|
||||||
.addSelect('transaction.balance_date', 'balanceDate')
|
.addSelect('transaction.balance_date', 'balanceDate')
|
||||||
.innerJoin(DbTransaction, 'transaction', 'user.id = transaction.user_id')
|
.innerJoin(DbTransaction, 'transaction', 'user.id = transaction.user_id')
|
||||||
.where(
|
.where(
|
||||||
`transaction.balance_date = (SELECT MAX(t.balance_date) FROM transactions AS t WHERE t.user_id = user.id)`,
|
`transaction.balance_date = (SELECT MAX(t.balance_date) FROM transactions AS t WHERE t.user_id = user.id)`,
|
||||||
)
|
)
|
||||||
.orderBy('transaction.balance_date', 'DESC')
|
.orderBy('transaction.balance_date', 'DESC')
|
||||||
.addOrderBy('transaction.id', 'DESC')
|
.addOrderBy('transaction.id', 'DESC')
|
||||||
.getRawMany()
|
.getRawMany()
|
||||||
|
|
||||||
const activeUsers = lastUserTransactions.length
|
const activeUsers = lastUserTransactions.length
|
||||||
|
|
||||||
lastUserTransactions.forEach(({ balance, balanceDate }) => {
|
lastUserTransactions.forEach(({ balance, balanceDate }) => {
|
||||||
const decay = calculateDecay(new Decimal(balance), new Date(balanceDate), receivedCallDate)
|
const decay = calculateDecay(new Decimal(balance), new Date(balanceDate), receivedCallDate)
|
||||||
if (decay) {
|
if (decay) {
|
||||||
totalGradidoAvailable = totalGradidoAvailable.plus(decay.balance.toString())
|
totalGradidoAvailable = totalGradidoAvailable.plus(decay.balance.toString())
|
||||||
totalGradidoUnbookedDecayed = totalGradidoUnbookedDecayed.plus(decay.decay.toString())
|
totalGradidoUnbookedDecayed = totalGradidoUnbookedDecayed.plus(decay.decay.toString())
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return {
|
||||||
|
activeUsers,
|
||||||
|
totalGradidoAvailable,
|
||||||
|
totalGradidoUnbookedDecayed,
|
||||||
}
|
}
|
||||||
})
|
} finally {
|
||||||
|
await queryRunner.release()
|
||||||
const { totalGradidoCreated } = await queryRunner.manager
|
|
||||||
.createQueryBuilder()
|
|
||||||
.select('SUM(transaction.amount) AS totalGradidoCreated')
|
|
||||||
.from(DbTransaction, 'transaction')
|
|
||||||
.where('transaction.typeId = 1')
|
|
||||||
.getRawOne()
|
|
||||||
|
|
||||||
const { totalGradidoDecayed } = await queryRunner.manager
|
|
||||||
.createQueryBuilder()
|
|
||||||
.select('SUM(transaction.decay) AS totalGradidoDecayed')
|
|
||||||
.from(DbTransaction, 'transaction')
|
|
||||||
.where('transaction.decay IS NOT NULL')
|
|
||||||
.getRawOne()
|
|
||||||
|
|
||||||
await queryRunner.release()
|
|
||||||
|
|
||||||
return {
|
|
||||||
totalUsers,
|
|
||||||
activeUsers,
|
|
||||||
deletedUsers,
|
|
||||||
totalGradidoCreated,
|
|
||||||
totalGradidoDecayed,
|
|
||||||
totalGradidoAvailable,
|
|
||||||
totalGradidoUnbookedDecayed,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,7 +4,7 @@
|
|||||||
import { transactionLinkCode } from './TransactionLinkResolver'
|
import { transactionLinkCode } from './TransactionLinkResolver'
|
||||||
import { bibiBloxberg } from '@/seeds/users/bibi-bloxberg'
|
import { bibiBloxberg } from '@/seeds/users/bibi-bloxberg'
|
||||||
import { peterLustig } from '@/seeds/users/peter-lustig'
|
import { peterLustig } from '@/seeds/users/peter-lustig'
|
||||||
import { cleanDB, testEnvironment, resetToken } from '@test/helpers'
|
import { cleanDB, testEnvironment, resetToken, resetEntity } from '@test/helpers'
|
||||||
import { creationFactory } from '@/seeds/factory/creation'
|
import { creationFactory } from '@/seeds/factory/creation'
|
||||||
import { creations } from '@/seeds/creation/index'
|
import { creations } from '@/seeds/creation/index'
|
||||||
import { userFactory } from '@/seeds/factory/user'
|
import { userFactory } from '@/seeds/factory/user'
|
||||||
@ -50,238 +50,340 @@ afterAll(async () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
describe('TransactionLinkResolver', () => {
|
describe('TransactionLinkResolver', () => {
|
||||||
// TODO: have this test separated into a transactionLink and a contributionLink part (if possible)
|
describe('redeemTransactionLink', () => {
|
||||||
describe('redeem daily Contribution Link', () => {
|
describe('contributionLink', () => {
|
||||||
const now = new Date()
|
describe('input not valid', () => {
|
||||||
let contributionLink: DbContributionLink | undefined
|
|
||||||
let contribution: UnconfirmedContribution | undefined
|
|
||||||
|
|
||||||
beforeAll(async () => {
|
|
||||||
await mutate({
|
|
||||||
mutation: login,
|
|
||||||
variables: { email: 'peter@lustig.de', password: 'Aa12345_' },
|
|
||||||
})
|
|
||||||
await mutate({
|
|
||||||
mutation: createContributionLink,
|
|
||||||
variables: {
|
|
||||||
amount: new Decimal(5),
|
|
||||||
name: 'Daily Contribution Link',
|
|
||||||
memo: 'Thank you for contribute daily to the community',
|
|
||||||
cycle: 'DAILY',
|
|
||||||
validFrom: new Date(now.getFullYear(), 0, 1).toISOString(),
|
|
||||||
validTo: new Date(now.getFullYear(), 11, 31, 23, 59, 59, 999).toISOString(),
|
|
||||||
maxAmountPerMonth: new Decimal(200),
|
|
||||||
maxPerCycle: 1,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
it('has a daily contribution link in the database', async () => {
|
|
||||||
const cls = await DbContributionLink.find()
|
|
||||||
expect(cls).toHaveLength(1)
|
|
||||||
contributionLink = cls[0]
|
|
||||||
expect(contributionLink).toEqual(
|
|
||||||
expect.objectContaining({
|
|
||||||
id: expect.any(Number),
|
|
||||||
name: 'Daily Contribution Link',
|
|
||||||
memo: 'Thank you for contribute daily to the community',
|
|
||||||
validFrom: new Date(now.getFullYear(), 0, 1),
|
|
||||||
validTo: new Date(now.getFullYear(), 11, 31, 23, 59, 59, 0),
|
|
||||||
cycle: 'DAILY',
|
|
||||||
maxPerCycle: 1,
|
|
||||||
totalMaxCountOfContribution: null,
|
|
||||||
maxAccountBalance: null,
|
|
||||||
minGapHours: null,
|
|
||||||
createdAt: expect.any(Date),
|
|
||||||
deletedAt: null,
|
|
||||||
code: expect.stringMatching(/^[0-9a-f]{24,24}$/),
|
|
||||||
linkEnabled: true,
|
|
||||||
amount: expect.decimalEqual(5),
|
|
||||||
maxAmountPerMonth: expect.decimalEqual(200),
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('user has pending contribution of 1000 GDD', () => {
|
|
||||||
beforeAll(async () => {
|
|
||||||
await mutate({
|
|
||||||
mutation: login,
|
|
||||||
variables: { email: 'bibi@bloxberg.de', password: 'Aa12345_' },
|
|
||||||
})
|
|
||||||
const result = await mutate({
|
|
||||||
mutation: createContribution,
|
|
||||||
variables: {
|
|
||||||
amount: new Decimal(1000),
|
|
||||||
memo: 'I was brewing potions for the community the whole month',
|
|
||||||
creationDate: now.toISOString(),
|
|
||||||
},
|
|
||||||
})
|
|
||||||
contribution = result.data.createContribution
|
|
||||||
})
|
|
||||||
|
|
||||||
it('does not allow the user to redeem the contribution link', async () => {
|
|
||||||
await expect(
|
|
||||||
mutate({
|
|
||||||
mutation: redeemTransactionLink,
|
|
||||||
variables: {
|
|
||||||
code: 'CL-' + (contributionLink ? contributionLink.code : ''),
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
).resolves.toMatchObject({
|
|
||||||
errors: [
|
|
||||||
new GraphQLError(
|
|
||||||
'Creation from contribution link was not successful. Error: The amount (5 GDD) to be created exceeds the amount (0 GDD) still available for this month.',
|
|
||||||
),
|
|
||||||
],
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('user has no pending contributions that would not allow to redeem the link', () => {
|
|
||||||
beforeAll(async () => {
|
|
||||||
await mutate({
|
|
||||||
mutation: login,
|
|
||||||
variables: { email: 'bibi@bloxberg.de', password: 'Aa12345_' },
|
|
||||||
})
|
|
||||||
await mutate({
|
|
||||||
mutation: updateContribution,
|
|
||||||
variables: {
|
|
||||||
contributionId: contribution ? contribution.id : -1,
|
|
||||||
amount: new Decimal(800),
|
|
||||||
memo: 'I was brewing potions for the community the whole month',
|
|
||||||
creationDate: now.toISOString(),
|
|
||||||
},
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
it('allows the user to redeem the contribution link', async () => {
|
|
||||||
await expect(
|
|
||||||
mutate({
|
|
||||||
mutation: redeemTransactionLink,
|
|
||||||
variables: {
|
|
||||||
code: 'CL-' + (contributionLink ? contributionLink.code : ''),
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
).resolves.toMatchObject({
|
|
||||||
data: {
|
|
||||||
redeemTransactionLink: true,
|
|
||||||
},
|
|
||||||
errors: undefined,
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
it('does not allow the user to redeem the contribution link a second time on the same day', async () => {
|
|
||||||
await expect(
|
|
||||||
mutate({
|
|
||||||
mutation: redeemTransactionLink,
|
|
||||||
variables: {
|
|
||||||
code: 'CL-' + (contributionLink ? contributionLink.code : ''),
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
).resolves.toMatchObject({
|
|
||||||
errors: [
|
|
||||||
new GraphQLError(
|
|
||||||
'Creation from contribution link was not successful. Error: Contribution link already redeemed today',
|
|
||||||
),
|
|
||||||
],
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('after one day', () => {
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
jest.useFakeTimers()
|
|
||||||
setTimeout(jest.fn(), 1000 * 60 * 60 * 24)
|
|
||||||
jest.runAllTimers()
|
|
||||||
await mutate({
|
await mutate({
|
||||||
mutation: login,
|
mutation: login,
|
||||||
variables: { email: 'bibi@bloxberg.de', password: 'Aa12345_' },
|
variables: { email: 'peter@lustig.de', password: 'Aa12345_' },
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
afterAll(() => {
|
it('throws error when link does not exists', async () => {
|
||||||
jest.useRealTimers()
|
|
||||||
})
|
|
||||||
|
|
||||||
it('allows the user to redeem the contribution link again', async () => {
|
|
||||||
await expect(
|
await expect(
|
||||||
mutate({
|
mutate({
|
||||||
mutation: redeemTransactionLink,
|
mutation: redeemTransactionLink,
|
||||||
variables: {
|
variables: {
|
||||||
code: 'CL-' + (contributionLink ? contributionLink.code : ''),
|
code: 'CL-123456',
|
||||||
},
|
|
||||||
}),
|
|
||||||
).resolves.toMatchObject({
|
|
||||||
data: {
|
|
||||||
redeemTransactionLink: true,
|
|
||||||
},
|
|
||||||
errors: undefined,
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
it('does not allow the user to redeem the contribution link a second time on the same day', async () => {
|
|
||||||
await expect(
|
|
||||||
mutate({
|
|
||||||
mutation: redeemTransactionLink,
|
|
||||||
variables: {
|
|
||||||
code: 'CL-' + (contributionLink ? contributionLink.code : ''),
|
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
).resolves.toMatchObject({
|
).resolves.toMatchObject({
|
||||||
errors: [
|
errors: [
|
||||||
new GraphQLError(
|
new GraphQLError(
|
||||||
'Creation from contribution link was not successful. Error: Contribution link already redeemed today',
|
'Creation from contribution link was not successful. Error: No contribution link found to given code: CL-123456',
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('throws error when link is not valid yet', async () => {
|
||||||
|
const now = new Date()
|
||||||
|
const {
|
||||||
|
data: { createContributionLink: contributionLink },
|
||||||
|
} = await mutate({
|
||||||
|
mutation: createContributionLink,
|
||||||
|
variables: {
|
||||||
|
amount: new Decimal(5),
|
||||||
|
name: 'Daily Contribution Link',
|
||||||
|
memo: 'Thank you for contribute daily to the community',
|
||||||
|
cycle: 'DAILY',
|
||||||
|
validFrom: new Date(now.getFullYear() + 1, 0, 1).toISOString(),
|
||||||
|
validTo: new Date(now.getFullYear() + 1, 11, 31, 23, 59, 59, 999).toISOString(),
|
||||||
|
maxAmountPerMonth: new Decimal(200),
|
||||||
|
maxPerCycle: 1,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
await expect(
|
||||||
|
mutate({
|
||||||
|
mutation: redeemTransactionLink,
|
||||||
|
variables: {
|
||||||
|
code: 'CL-' + contributionLink.code,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
).resolves.toMatchObject({
|
||||||
|
errors: [
|
||||||
|
new GraphQLError(
|
||||||
|
'Creation from contribution link was not successful. Error: Contribution link not valid yet',
|
||||||
|
),
|
||||||
|
],
|
||||||
|
})
|
||||||
|
await resetEntity(DbContributionLink)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('throws error when contributionLink cycle is invalid', async () => {
|
||||||
|
const now = new Date()
|
||||||
|
const {
|
||||||
|
data: { createContributionLink: contributionLink },
|
||||||
|
} = await mutate({
|
||||||
|
mutation: createContributionLink,
|
||||||
|
variables: {
|
||||||
|
amount: new Decimal(5),
|
||||||
|
name: 'Daily Contribution Link',
|
||||||
|
memo: 'Thank you for contribute daily to the community',
|
||||||
|
cycle: 'INVALID',
|
||||||
|
validFrom: new Date(now.getFullYear(), 0, 1).toISOString(),
|
||||||
|
validTo: new Date(now.getFullYear(), 11, 31, 23, 59, 59, 999).toISOString(),
|
||||||
|
maxAmountPerMonth: new Decimal(200),
|
||||||
|
maxPerCycle: 1,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
await expect(
|
||||||
|
mutate({
|
||||||
|
mutation: redeemTransactionLink,
|
||||||
|
variables: {
|
||||||
|
code: 'CL-' + contributionLink.code,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
).resolves.toMatchObject({
|
||||||
|
errors: [
|
||||||
|
new GraphQLError(
|
||||||
|
'Creation from contribution link was not successful. Error: Contribution link has unknown cycle',
|
||||||
|
),
|
||||||
|
],
|
||||||
|
})
|
||||||
|
await resetEntity(DbContributionLink)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('throws error when link is no longer valid', async () => {
|
||||||
|
const now = new Date()
|
||||||
|
const {
|
||||||
|
data: { createContributionLink: contributionLink },
|
||||||
|
} = await mutate({
|
||||||
|
mutation: createContributionLink,
|
||||||
|
variables: {
|
||||||
|
amount: new Decimal(5),
|
||||||
|
name: 'Daily Contribution Link',
|
||||||
|
memo: 'Thank you for contribute daily to the community',
|
||||||
|
cycle: 'DAILY',
|
||||||
|
validFrom: new Date(now.getFullYear() - 1, 0, 1).toISOString(),
|
||||||
|
validTo: new Date(now.getFullYear() - 1, 11, 31, 23, 59, 59, 999).toISOString(),
|
||||||
|
maxAmountPerMonth: new Decimal(200),
|
||||||
|
maxPerCycle: 1,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
await expect(
|
||||||
|
mutate({
|
||||||
|
mutation: redeemTransactionLink,
|
||||||
|
variables: {
|
||||||
|
code: 'CL-' + contributionLink.code,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
).resolves.toMatchObject({
|
||||||
|
errors: [
|
||||||
|
new GraphQLError(
|
||||||
|
'Creation from contribution link was not successful. Error: Contribution link is no longer valid',
|
||||||
|
),
|
||||||
|
],
|
||||||
|
})
|
||||||
|
await resetEntity(DbContributionLink)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('transaction links list', () => {
|
// TODO: have this test separated into a transactionLink and a contributionLink part
|
||||||
const variables = {
|
describe('redeem daily Contribution Link', () => {
|
||||||
userId: 1, // dummy, may be replaced
|
const now = new Date()
|
||||||
filters: null,
|
let contributionLink: DbContributionLink | undefined
|
||||||
currentPage: 1,
|
let contribution: UnconfirmedContribution | undefined
|
||||||
pageSize: 5,
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: there is a test not cleaning up after itself! Fix it!
|
|
||||||
beforeAll(async () => {
|
|
||||||
await cleanDB()
|
|
||||||
resetToken()
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('unauthenticated', () => {
|
|
||||||
it('returns an error', async () => {
|
|
||||||
await expect(
|
|
||||||
query({
|
|
||||||
query: listTransactionLinksAdmin,
|
|
||||||
variables,
|
|
||||||
}),
|
|
||||||
).resolves.toEqual(
|
|
||||||
expect.objectContaining({
|
|
||||||
errors: [new GraphQLError('401 Unauthorized')],
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('authenticated', () => {
|
|
||||||
describe('without admin rights', () => {
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
user = await userFactory(testEnv, bibiBloxberg)
|
|
||||||
await mutate({
|
await mutate({
|
||||||
mutation: login,
|
mutation: login,
|
||||||
variables: { email: 'bibi@bloxberg.de', password: 'Aa12345_' },
|
variables: { email: 'peter@lustig.de', password: 'Aa12345_' },
|
||||||
|
})
|
||||||
|
await mutate({
|
||||||
|
mutation: createContributionLink,
|
||||||
|
variables: {
|
||||||
|
amount: new Decimal(5),
|
||||||
|
name: 'Daily Contribution Link',
|
||||||
|
memo: 'Thank you for contribute daily to the community',
|
||||||
|
cycle: 'DAILY',
|
||||||
|
validFrom: new Date(now.getFullYear(), 0, 1).toISOString(),
|
||||||
|
validTo: new Date(now.getFullYear(), 11, 31, 23, 59, 59, 999).toISOString(),
|
||||||
|
maxAmountPerMonth: new Decimal(200),
|
||||||
|
maxPerCycle: 1,
|
||||||
|
},
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
afterAll(async () => {
|
it('has a daily contribution link in the database', async () => {
|
||||||
await cleanDB()
|
const cls = await DbContributionLink.find()
|
||||||
resetToken()
|
expect(cls).toHaveLength(1)
|
||||||
|
contributionLink = cls[0]
|
||||||
|
expect(contributionLink).toEqual(
|
||||||
|
expect.objectContaining({
|
||||||
|
id: expect.any(Number),
|
||||||
|
name: 'Daily Contribution Link',
|
||||||
|
memo: 'Thank you for contribute daily to the community',
|
||||||
|
validFrom: new Date(now.getFullYear(), 0, 1),
|
||||||
|
validTo: new Date(now.getFullYear(), 11, 31, 23, 59, 59, 0),
|
||||||
|
cycle: 'DAILY',
|
||||||
|
maxPerCycle: 1,
|
||||||
|
totalMaxCountOfContribution: null,
|
||||||
|
maxAccountBalance: null,
|
||||||
|
minGapHours: null,
|
||||||
|
createdAt: expect.any(Date),
|
||||||
|
deletedAt: null,
|
||||||
|
code: expect.stringMatching(/^[0-9a-f]{24,24}$/),
|
||||||
|
linkEnabled: true,
|
||||||
|
amount: expect.decimalEqual(5),
|
||||||
|
maxAmountPerMonth: expect.decimalEqual(200),
|
||||||
|
}),
|
||||||
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('user has pending contribution of 1000 GDD', () => {
|
||||||
|
beforeAll(async () => {
|
||||||
|
await mutate({
|
||||||
|
mutation: login,
|
||||||
|
variables: { email: 'bibi@bloxberg.de', password: 'Aa12345_' },
|
||||||
|
})
|
||||||
|
const result = await mutate({
|
||||||
|
mutation: createContribution,
|
||||||
|
variables: {
|
||||||
|
amount: new Decimal(1000),
|
||||||
|
memo: 'I was brewing potions for the community the whole month',
|
||||||
|
creationDate: now.toISOString(),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
contribution = result.data.createContribution
|
||||||
|
})
|
||||||
|
|
||||||
|
it('does not allow the user to redeem the contribution link', async () => {
|
||||||
|
await expect(
|
||||||
|
mutate({
|
||||||
|
mutation: redeemTransactionLink,
|
||||||
|
variables: {
|
||||||
|
code: 'CL-' + (contributionLink ? contributionLink.code : ''),
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
).resolves.toMatchObject({
|
||||||
|
errors: [
|
||||||
|
new GraphQLError(
|
||||||
|
'Creation from contribution link was not successful. Error: The amount (5 GDD) to be created exceeds the amount (0 GDD) still available for this month.',
|
||||||
|
),
|
||||||
|
],
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('user has no pending contributions that would not allow to redeem the link', () => {
|
||||||
|
beforeAll(async () => {
|
||||||
|
await mutate({
|
||||||
|
mutation: login,
|
||||||
|
variables: { email: 'bibi@bloxberg.de', password: 'Aa12345_' },
|
||||||
|
})
|
||||||
|
await mutate({
|
||||||
|
mutation: updateContribution,
|
||||||
|
variables: {
|
||||||
|
contributionId: contribution ? contribution.id : -1,
|
||||||
|
amount: new Decimal(800),
|
||||||
|
memo: 'I was brewing potions for the community the whole month',
|
||||||
|
creationDate: now.toISOString(),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('allows the user to redeem the contribution link', async () => {
|
||||||
|
await expect(
|
||||||
|
mutate({
|
||||||
|
mutation: redeemTransactionLink,
|
||||||
|
variables: {
|
||||||
|
code: 'CL-' + (contributionLink ? contributionLink.code : ''),
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
).resolves.toMatchObject({
|
||||||
|
data: {
|
||||||
|
redeemTransactionLink: true,
|
||||||
|
},
|
||||||
|
errors: undefined,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('does not allow the user to redeem the contribution link a second time on the same day', async () => {
|
||||||
|
await expect(
|
||||||
|
mutate({
|
||||||
|
mutation: redeemTransactionLink,
|
||||||
|
variables: {
|
||||||
|
code: 'CL-' + (contributionLink ? contributionLink.code : ''),
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
).resolves.toMatchObject({
|
||||||
|
errors: [
|
||||||
|
new GraphQLError(
|
||||||
|
'Creation from contribution link was not successful. Error: Contribution link already redeemed today',
|
||||||
|
),
|
||||||
|
],
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('after one day', () => {
|
||||||
|
beforeAll(async () => {
|
||||||
|
jest.useFakeTimers()
|
||||||
|
setTimeout(jest.fn(), 1000 * 60 * 60 * 24)
|
||||||
|
jest.runAllTimers()
|
||||||
|
await mutate({
|
||||||
|
mutation: login,
|
||||||
|
variables: { email: 'bibi@bloxberg.de', password: 'Aa12345_' },
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
afterAll(() => {
|
||||||
|
jest.useRealTimers()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('allows the user to redeem the contribution link again', async () => {
|
||||||
|
await expect(
|
||||||
|
mutate({
|
||||||
|
mutation: redeemTransactionLink,
|
||||||
|
variables: {
|
||||||
|
code: 'CL-' + (contributionLink ? contributionLink.code : ''),
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
).resolves.toMatchObject({
|
||||||
|
data: {
|
||||||
|
redeemTransactionLink: true,
|
||||||
|
},
|
||||||
|
errors: undefined,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('does not allow the user to redeem the contribution link a second time on the same day', async () => {
|
||||||
|
await expect(
|
||||||
|
mutate({
|
||||||
|
mutation: redeemTransactionLink,
|
||||||
|
variables: {
|
||||||
|
code: 'CL-' + (contributionLink ? contributionLink.code : ''),
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
).resolves.toMatchObject({
|
||||||
|
errors: [
|
||||||
|
new GraphQLError(
|
||||||
|
'Creation from contribution link was not successful. Error: Contribution link already redeemed today',
|
||||||
|
),
|
||||||
|
],
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('transaction links list', () => {
|
||||||
|
const variables = {
|
||||||
|
userId: 1, // dummy, may be replaced
|
||||||
|
filters: null,
|
||||||
|
currentPage: 1,
|
||||||
|
pageSize: 5,
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: there is a test not cleaning up after itself! Fix it!
|
||||||
|
beforeAll(async () => {
|
||||||
|
await cleanDB()
|
||||||
|
resetToken()
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('unauthenticated', () => {
|
||||||
it('returns an error', async () => {
|
it('returns an error', async () => {
|
||||||
await expect(
|
await expect(
|
||||||
query({
|
query({
|
||||||
@ -296,40 +398,22 @@ describe('TransactionLinkResolver', () => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('with admin rights', () => {
|
describe('authenticated', () => {
|
||||||
beforeAll(async () => {
|
describe('without admin rights', () => {
|
||||||
// admin 'peter@lustig.de' has to exists for 'creationFactory'
|
beforeAll(async () => {
|
||||||
await userFactory(testEnv, peterLustig)
|
user = await userFactory(testEnv, bibiBloxberg)
|
||||||
|
await mutate({
|
||||||
user = await userFactory(testEnv, bibiBloxberg)
|
mutation: login,
|
||||||
variables.userId = user.id
|
variables: { email: 'bibi@bloxberg.de', password: 'Aa12345_' },
|
||||||
variables.pageSize = 25
|
})
|
||||||
// bibi needs GDDs
|
|
||||||
const bibisCreation = creations.find((creation) => creation.email === 'bibi@bloxberg.de')
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
||||||
await creationFactory(testEnv, bibisCreation!)
|
|
||||||
// bibis transaktion links
|
|
||||||
const bibisTransaktionLinks = transactionLinks.filter(
|
|
||||||
(transactionLink) => transactionLink.email === 'bibi@bloxberg.de',
|
|
||||||
)
|
|
||||||
for (let i = 0; i < bibisTransaktionLinks.length; i++) {
|
|
||||||
await transactionLinkFactory(testEnv, bibisTransaktionLinks[i])
|
|
||||||
}
|
|
||||||
|
|
||||||
// admin: only now log in
|
|
||||||
await mutate({
|
|
||||||
mutation: login,
|
|
||||||
variables: { email: 'peter@lustig.de', password: 'Aa12345_' },
|
|
||||||
})
|
})
|
||||||
})
|
|
||||||
|
|
||||||
afterAll(async () => {
|
afterAll(async () => {
|
||||||
await cleanDB()
|
await cleanDB()
|
||||||
resetToken()
|
resetToken()
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('without any filters', () => {
|
it('returns an error', async () => {
|
||||||
it('finds 6 open transaction links and no deleted or redeemed', async () => {
|
|
||||||
await expect(
|
await expect(
|
||||||
query({
|
query({
|
||||||
query: listTransactionLinksAdmin,
|
query: listTransactionLinksAdmin,
|
||||||
@ -337,185 +421,235 @@ describe('TransactionLinkResolver', () => {
|
|||||||
}),
|
}),
|
||||||
).resolves.toEqual(
|
).resolves.toEqual(
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
data: {
|
errors: [new GraphQLError('401 Unauthorized')],
|
||||||
listTransactionLinksAdmin: {
|
|
||||||
linkCount: 6,
|
|
||||||
linkList: expect.not.arrayContaining([
|
|
||||||
expect.objectContaining({
|
|
||||||
memo: 'Leider wollte niemand meine Gradidos zum Neujahr haben :(',
|
|
||||||
createdAt: expect.any(String),
|
|
||||||
}),
|
|
||||||
expect.objectContaining({
|
|
||||||
memo: 'Da habe ich mich wohl etwas übernommen.',
|
|
||||||
deletedAt: expect.any(String),
|
|
||||||
}),
|
|
||||||
]),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('all filters are null', () => {
|
describe('with admin rights', () => {
|
||||||
it('finds 6 open transaction links and no deleted or redeemed', async () => {
|
beforeAll(async () => {
|
||||||
await expect(
|
// admin 'peter@lustig.de' has to exists for 'creationFactory'
|
||||||
query({
|
await userFactory(testEnv, peterLustig)
|
||||||
query: listTransactionLinksAdmin,
|
|
||||||
variables: {
|
|
||||||
...variables,
|
|
||||||
filters: {
|
|
||||||
withDeleted: null,
|
|
||||||
withExpired: null,
|
|
||||||
withRedeemed: null,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
).resolves.toEqual(
|
|
||||||
expect.objectContaining({
|
|
||||||
data: {
|
|
||||||
listTransactionLinksAdmin: {
|
|
||||||
linkCount: 6,
|
|
||||||
linkList: expect.not.arrayContaining([
|
|
||||||
expect.objectContaining({
|
|
||||||
memo: 'Leider wollte niemand meine Gradidos zum Neujahr haben :(',
|
|
||||||
createdAt: expect.any(String),
|
|
||||||
}),
|
|
||||||
expect.objectContaining({
|
|
||||||
memo: 'Da habe ich mich wohl etwas übernommen.',
|
|
||||||
deletedAt: expect.any(String),
|
|
||||||
}),
|
|
||||||
]),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('filter with deleted', () => {
|
user = await userFactory(testEnv, bibiBloxberg)
|
||||||
it('finds 6 open transaction links, 1 deleted, and no redeemed', async () => {
|
variables.userId = user.id
|
||||||
await expect(
|
variables.pageSize = 25
|
||||||
query({
|
// bibi needs GDDs
|
||||||
query: listTransactionLinksAdmin,
|
const bibisCreation = creations.find(
|
||||||
variables: {
|
(creation) => creation.email === 'bibi@bloxberg.de',
|
||||||
...variables,
|
|
||||||
filters: {
|
|
||||||
withDeleted: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
).resolves.toEqual(
|
|
||||||
expect.objectContaining({
|
|
||||||
data: {
|
|
||||||
listTransactionLinksAdmin: {
|
|
||||||
linkCount: 7,
|
|
||||||
linkList: expect.arrayContaining([
|
|
||||||
expect.not.objectContaining({
|
|
||||||
memo: 'Leider wollte niemand meine Gradidos zum Neujahr haben :(',
|
|
||||||
createdAt: expect.any(String),
|
|
||||||
}),
|
|
||||||
expect.objectContaining({
|
|
||||||
memo: 'Da habe ich mich wohl etwas übernommen.',
|
|
||||||
deletedAt: expect.any(String),
|
|
||||||
}),
|
|
||||||
]),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
)
|
)
|
||||||
})
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||||
})
|
await creationFactory(testEnv, bibisCreation!)
|
||||||
|
// bibis transaktion links
|
||||||
|
const bibisTransaktionLinks = transactionLinks.filter(
|
||||||
|
(transactionLink) => transactionLink.email === 'bibi@bloxberg.de',
|
||||||
|
)
|
||||||
|
for (let i = 0; i < bibisTransaktionLinks.length; i++) {
|
||||||
|
await transactionLinkFactory(testEnv, bibisTransaktionLinks[i])
|
||||||
|
}
|
||||||
|
|
||||||
describe('filter by expired', () => {
|
// admin: only now log in
|
||||||
it('finds 5 open transaction links, 1 expired, and no redeemed', async () => {
|
await mutate({
|
||||||
await expect(
|
mutation: login,
|
||||||
query({
|
variables: { email: 'peter@lustig.de', password: 'Aa12345_' },
|
||||||
query: listTransactionLinksAdmin,
|
})
|
||||||
variables: {
|
|
||||||
...variables,
|
|
||||||
filters: {
|
|
||||||
withExpired: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
).resolves.toEqual(
|
|
||||||
expect.objectContaining({
|
|
||||||
data: {
|
|
||||||
listTransactionLinksAdmin: {
|
|
||||||
linkCount: 7,
|
|
||||||
linkList: expect.arrayContaining([
|
|
||||||
expect.objectContaining({
|
|
||||||
memo: 'Leider wollte niemand meine Gradidos zum Neujahr haben :(',
|
|
||||||
createdAt: expect.any(String),
|
|
||||||
}),
|
|
||||||
expect.not.objectContaining({
|
|
||||||
memo: 'Da habe ich mich wohl etwas übernommen.',
|
|
||||||
deletedAt: expect.any(String),
|
|
||||||
}),
|
|
||||||
]),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
})
|
})
|
||||||
})
|
|
||||||
|
|
||||||
// TODO: works not as expected, because 'redeemedAt' and 'redeemedBy' have to be added to the transaktion link factory
|
afterAll(async () => {
|
||||||
describe.skip('filter by redeemed', () => {
|
await cleanDB()
|
||||||
it('finds 6 open transaction links, 1 deleted, and no redeemed', async () => {
|
resetToken()
|
||||||
await expect(
|
})
|
||||||
query({
|
|
||||||
query: listTransactionLinksAdmin,
|
describe('without any filters', () => {
|
||||||
variables: {
|
it('finds 6 open transaction links and no deleted or redeemed', async () => {
|
||||||
...variables,
|
await expect(
|
||||||
filters: {
|
query({
|
||||||
withDeleted: null,
|
query: listTransactionLinksAdmin,
|
||||||
withExpired: null,
|
variables,
|
||||||
withRedeemed: true,
|
}),
|
||||||
|
).resolves.toEqual(
|
||||||
|
expect.objectContaining({
|
||||||
|
data: {
|
||||||
|
listTransactionLinksAdmin: {
|
||||||
|
linkCount: 6,
|
||||||
|
linkList: expect.not.arrayContaining([
|
||||||
|
expect.objectContaining({
|
||||||
|
memo: 'Leider wollte niemand meine Gradidos zum Neujahr haben :(',
|
||||||
|
createdAt: expect.any(String),
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
memo: 'Da habe ich mich wohl etwas übernommen.',
|
||||||
|
deletedAt: expect.any(String),
|
||||||
|
}),
|
||||||
|
]),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
}),
|
||||||
}),
|
)
|
||||||
).resolves.toEqual(
|
})
|
||||||
expect.objectContaining({
|
})
|
||||||
data: {
|
|
||||||
listTransactionLinksAdmin: {
|
describe('all filters are null', () => {
|
||||||
linkCount: 6,
|
it('finds 6 open transaction links and no deleted or redeemed', async () => {
|
||||||
linkList: expect.arrayContaining([
|
await expect(
|
||||||
expect.not.objectContaining({
|
query({
|
||||||
memo: 'Leider wollte niemand meine Gradidos zum Neujahr haben :(',
|
query: listTransactionLinksAdmin,
|
||||||
createdAt: expect.any(String),
|
variables: {
|
||||||
}),
|
...variables,
|
||||||
expect.objectContaining({
|
filters: {
|
||||||
memo: 'Yeah, eingelöst!',
|
withDeleted: null,
|
||||||
redeemedAt: expect.any(String),
|
withExpired: null,
|
||||||
redeemedBy: expect.any(Number),
|
withRedeemed: null,
|
||||||
}),
|
},
|
||||||
expect.not.objectContaining({
|
|
||||||
memo: 'Da habe ich mich wohl etwas übernommen.',
|
|
||||||
deletedAt: expect.any(String),
|
|
||||||
}),
|
|
||||||
]),
|
|
||||||
},
|
},
|
||||||
},
|
}),
|
||||||
}),
|
).resolves.toEqual(
|
||||||
)
|
expect.objectContaining({
|
||||||
|
data: {
|
||||||
|
listTransactionLinksAdmin: {
|
||||||
|
linkCount: 6,
|
||||||
|
linkList: expect.not.arrayContaining([
|
||||||
|
expect.objectContaining({
|
||||||
|
memo: 'Leider wollte niemand meine Gradidos zum Neujahr haben :(',
|
||||||
|
createdAt: expect.any(String),
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
memo: 'Da habe ich mich wohl etwas übernommen.',
|
||||||
|
deletedAt: expect.any(String),
|
||||||
|
}),
|
||||||
|
]),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('filter with deleted', () => {
|
||||||
|
it('finds 6 open transaction links, 1 deleted, and no redeemed', async () => {
|
||||||
|
await expect(
|
||||||
|
query({
|
||||||
|
query: listTransactionLinksAdmin,
|
||||||
|
variables: {
|
||||||
|
...variables,
|
||||||
|
filters: {
|
||||||
|
withDeleted: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
).resolves.toEqual(
|
||||||
|
expect.objectContaining({
|
||||||
|
data: {
|
||||||
|
listTransactionLinksAdmin: {
|
||||||
|
linkCount: 7,
|
||||||
|
linkList: expect.arrayContaining([
|
||||||
|
expect.not.objectContaining({
|
||||||
|
memo: 'Leider wollte niemand meine Gradidos zum Neujahr haben :(',
|
||||||
|
createdAt: expect.any(String),
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
memo: 'Da habe ich mich wohl etwas übernommen.',
|
||||||
|
deletedAt: expect.any(String),
|
||||||
|
}),
|
||||||
|
]),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('filter by expired', () => {
|
||||||
|
it('finds 5 open transaction links, 1 expired, and no redeemed', async () => {
|
||||||
|
await expect(
|
||||||
|
query({
|
||||||
|
query: listTransactionLinksAdmin,
|
||||||
|
variables: {
|
||||||
|
...variables,
|
||||||
|
filters: {
|
||||||
|
withExpired: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
).resolves.toEqual(
|
||||||
|
expect.objectContaining({
|
||||||
|
data: {
|
||||||
|
listTransactionLinksAdmin: {
|
||||||
|
linkCount: 7,
|
||||||
|
linkList: expect.arrayContaining([
|
||||||
|
expect.objectContaining({
|
||||||
|
memo: 'Leider wollte niemand meine Gradidos zum Neujahr haben :(',
|
||||||
|
createdAt: expect.any(String),
|
||||||
|
}),
|
||||||
|
expect.not.objectContaining({
|
||||||
|
memo: 'Da habe ich mich wohl etwas übernommen.',
|
||||||
|
deletedAt: expect.any(String),
|
||||||
|
}),
|
||||||
|
]),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
// TODO: works not as expected, because 'redeemedAt' and 'redeemedBy' have to be added to the transaktion link factory
|
||||||
|
describe.skip('filter by redeemed', () => {
|
||||||
|
it('finds 6 open transaction links, 1 deleted, and no redeemed', async () => {
|
||||||
|
await expect(
|
||||||
|
query({
|
||||||
|
query: listTransactionLinksAdmin,
|
||||||
|
variables: {
|
||||||
|
...variables,
|
||||||
|
filters: {
|
||||||
|
withDeleted: null,
|
||||||
|
withExpired: null,
|
||||||
|
withRedeemed: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
).resolves.toEqual(
|
||||||
|
expect.objectContaining({
|
||||||
|
data: {
|
||||||
|
listTransactionLinksAdmin: {
|
||||||
|
linkCount: 6,
|
||||||
|
linkList: expect.arrayContaining([
|
||||||
|
expect.not.objectContaining({
|
||||||
|
memo: 'Leider wollte niemand meine Gradidos zum Neujahr haben :(',
|
||||||
|
createdAt: expect.any(String),
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
memo: 'Yeah, eingelöst!',
|
||||||
|
redeemedAt: expect.any(String),
|
||||||
|
redeemedBy: expect.any(Number),
|
||||||
|
}),
|
||||||
|
expect.not.objectContaining({
|
||||||
|
memo: 'Da habe ich mich wohl etwas übernommen.',
|
||||||
|
deletedAt: expect.any(String),
|
||||||
|
}),
|
||||||
|
]),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
|
||||||
|
|
||||||
describe('transactionLinkCode', () => {
|
describe('transactionLinkCode', () => {
|
||||||
const date = new Date()
|
const date = new Date()
|
||||||
|
|
||||||
it('returns a string of length 24', () => {
|
it('returns a string of length 24', () => {
|
||||||
expect(transactionLinkCode(date)).toHaveLength(24)
|
expect(transactionLinkCode(date)).toHaveLength(24)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('returns a string that ends with the hex value of date', () => {
|
it('returns a string that ends with the hex value of date', () => {
|
||||||
const regexp = new RegExp(date.getTime().toString(16) + '$')
|
const regexp = new RegExp(date.getTime().toString(16) + '$')
|
||||||
expect(transactionLinkCode(date)).toEqual(expect.stringMatching(regexp))
|
expect(transactionLinkCode(date)).toEqual(expect.stringMatching(regexp))
|
||||||
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@ -170,148 +170,154 @@ export class TransactionLinkResolver {
|
|||||||
if (code.match(/^CL-/)) {
|
if (code.match(/^CL-/)) {
|
||||||
// acquire lock
|
// acquire lock
|
||||||
const releaseLock = await TRANSACTIONS_LOCK.acquire()
|
const releaseLock = await TRANSACTIONS_LOCK.acquire()
|
||||||
logger.info('redeem contribution link...')
|
|
||||||
const now = new Date()
|
|
||||||
const queryRunner = getConnection().createQueryRunner()
|
|
||||||
await queryRunner.connect()
|
|
||||||
await queryRunner.startTransaction('REPEATABLE READ')
|
|
||||||
try {
|
try {
|
||||||
const contributionLink = await queryRunner.manager
|
logger.info('redeem contribution link...')
|
||||||
.createQueryBuilder()
|
const now = new Date()
|
||||||
.select('contributionLink')
|
const queryRunner = getConnection().createQueryRunner()
|
||||||
.from(DbContributionLink, 'contributionLink')
|
await queryRunner.connect()
|
||||||
.where('contributionLink.code = :code', { code: code.replace('CL-', '') })
|
await queryRunner.startTransaction('REPEATABLE READ')
|
||||||
.getOne()
|
try {
|
||||||
if (!contributionLink) {
|
const contributionLink = await queryRunner.manager
|
||||||
logger.error('no contribution link found to given code:', code)
|
.createQueryBuilder()
|
||||||
throw new Error('No contribution link found')
|
.select('contributionLink')
|
||||||
}
|
.from(DbContributionLink, 'contributionLink')
|
||||||
logger.info('...contribution link found with id', contributionLink.id)
|
.where('contributionLink.code = :code', { code: code.replace('CL-', '') })
|
||||||
if (new Date(contributionLink.validFrom).getTime() > now.getTime()) {
|
.getOne()
|
||||||
logger.error(
|
if (!contributionLink) {
|
||||||
'contribution link is not valid yet. Valid from: ',
|
logger.error('no contribution link found to given code:', code)
|
||||||
contributionLink.validFrom,
|
throw new Error(`No contribution link found to given code: ${code}`)
|
||||||
)
|
|
||||||
throw new Error('Contribution link not valid yet')
|
|
||||||
}
|
|
||||||
if (contributionLink.validTo) {
|
|
||||||
if (new Date(contributionLink.validTo).setHours(23, 59, 59) < now.getTime()) {
|
|
||||||
logger.error('contribution link is depricated. Valid to: ', contributionLink.validTo)
|
|
||||||
throw new Error('Contribution link is depricated')
|
|
||||||
}
|
}
|
||||||
}
|
logger.info('...contribution link found with id', contributionLink.id)
|
||||||
let alreadyRedeemed: DbContribution | undefined
|
if (new Date(contributionLink.validFrom).getTime() > now.getTime()) {
|
||||||
switch (contributionLink.cycle) {
|
logger.error(
|
||||||
case ContributionCycleType.ONCE: {
|
'contribution link is not valid yet. Valid from: ',
|
||||||
alreadyRedeemed = await queryRunner.manager
|
contributionLink.validFrom,
|
||||||
.createQueryBuilder()
|
)
|
||||||
.select('contribution')
|
throw new Error('Contribution link not valid yet')
|
||||||
.from(DbContribution, 'contribution')
|
}
|
||||||
.where('contribution.contributionLinkId = :linkId AND contribution.userId = :id', {
|
if (contributionLink.validTo) {
|
||||||
linkId: contributionLink.id,
|
if (new Date(contributionLink.validTo).setHours(23, 59, 59) < now.getTime()) {
|
||||||
id: user.id,
|
|
||||||
})
|
|
||||||
.getOne()
|
|
||||||
if (alreadyRedeemed) {
|
|
||||||
logger.error(
|
logger.error(
|
||||||
'contribution link with rule ONCE already redeemed by user with id',
|
'contribution link is no longer valid. Valid to: ',
|
||||||
user.id,
|
contributionLink.validTo,
|
||||||
)
|
)
|
||||||
throw new Error('Contribution link already redeemed')
|
throw new Error('Contribution link is no longer valid')
|
||||||
}
|
}
|
||||||
break
|
|
||||||
}
|
}
|
||||||
case ContributionCycleType.DAILY: {
|
let alreadyRedeemed: DbContribution | undefined
|
||||||
const start = new Date()
|
switch (contributionLink.cycle) {
|
||||||
start.setHours(0, 0, 0, 0)
|
case ContributionCycleType.ONCE: {
|
||||||
const end = new Date()
|
alreadyRedeemed = await queryRunner.manager
|
||||||
end.setHours(23, 59, 59, 999)
|
.createQueryBuilder()
|
||||||
alreadyRedeemed = await queryRunner.manager
|
.select('contribution')
|
||||||
.createQueryBuilder()
|
.from(DbContribution, 'contribution')
|
||||||
.select('contribution')
|
.where('contribution.contributionLinkId = :linkId AND contribution.userId = :id', {
|
||||||
.from(DbContribution, 'contribution')
|
|
||||||
.where(
|
|
||||||
`contribution.contributionLinkId = :linkId AND contribution.userId = :id
|
|
||||||
AND Date(contribution.confirmedAt) BETWEEN :start AND :end`,
|
|
||||||
{
|
|
||||||
linkId: contributionLink.id,
|
linkId: contributionLink.id,
|
||||||
id: user.id,
|
id: user.id,
|
||||||
start,
|
})
|
||||||
end,
|
.getOne()
|
||||||
},
|
if (alreadyRedeemed) {
|
||||||
)
|
logger.error(
|
||||||
.getOne()
|
'contribution link with rule ONCE already redeemed by user with id',
|
||||||
if (alreadyRedeemed) {
|
user.id,
|
||||||
logger.error(
|
)
|
||||||
'contribution link with rule DAILY already redeemed by user with id',
|
throw new Error('Contribution link already redeemed')
|
||||||
user.id,
|
}
|
||||||
)
|
break
|
||||||
throw new Error('Contribution link already redeemed today')
|
}
|
||||||
|
case ContributionCycleType.DAILY: {
|
||||||
|
const start = new Date()
|
||||||
|
start.setHours(0, 0, 0, 0)
|
||||||
|
const end = new Date()
|
||||||
|
end.setHours(23, 59, 59, 999)
|
||||||
|
alreadyRedeemed = await queryRunner.manager
|
||||||
|
.createQueryBuilder()
|
||||||
|
.select('contribution')
|
||||||
|
.from(DbContribution, 'contribution')
|
||||||
|
.where(
|
||||||
|
`contribution.contributionLinkId = :linkId AND contribution.userId = :id
|
||||||
|
AND Date(contribution.confirmedAt) BETWEEN :start AND :end`,
|
||||||
|
{
|
||||||
|
linkId: contributionLink.id,
|
||||||
|
id: user.id,
|
||||||
|
start,
|
||||||
|
end,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.getOne()
|
||||||
|
if (alreadyRedeemed) {
|
||||||
|
logger.error(
|
||||||
|
'contribution link with rule DAILY already redeemed by user with id',
|
||||||
|
user.id,
|
||||||
|
)
|
||||||
|
throw new Error('Contribution link already redeemed today')
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
logger.error('contribution link has unknown cycle', contributionLink.cycle)
|
||||||
|
throw new Error('Contribution link has unknown cycle')
|
||||||
}
|
}
|
||||||
break
|
|
||||||
}
|
}
|
||||||
default: {
|
|
||||||
logger.error('contribution link has unknown cycle', contributionLink.cycle)
|
const creations = await getUserCreation(user.id, clientTimezoneOffset)
|
||||||
throw new Error('Contribution link has unknown cycle')
|
logger.info('open creations', creations)
|
||||||
|
validateContribution(creations, contributionLink.amount, now, clientTimezoneOffset)
|
||||||
|
const contribution = new DbContribution()
|
||||||
|
contribution.userId = user.id
|
||||||
|
contribution.createdAt = now
|
||||||
|
contribution.contributionDate = now
|
||||||
|
contribution.memo = contributionLink.memo
|
||||||
|
contribution.amount = contributionLink.amount
|
||||||
|
contribution.contributionLinkId = contributionLink.id
|
||||||
|
contribution.contributionType = ContributionType.LINK
|
||||||
|
contribution.contributionStatus = ContributionStatus.CONFIRMED
|
||||||
|
|
||||||
|
await queryRunner.manager.insert(DbContribution, contribution)
|
||||||
|
|
||||||
|
const lastTransaction = await queryRunner.manager
|
||||||
|
.createQueryBuilder()
|
||||||
|
.select('transaction')
|
||||||
|
.from(DbTransaction, 'transaction')
|
||||||
|
.where('transaction.userId = :id', { id: user.id })
|
||||||
|
.orderBy('transaction.id', 'DESC')
|
||||||
|
.getOne()
|
||||||
|
let newBalance = new Decimal(0)
|
||||||
|
|
||||||
|
let decay: Decay | null = null
|
||||||
|
if (lastTransaction) {
|
||||||
|
decay = calculateDecay(lastTransaction.balance, lastTransaction.balanceDate, now)
|
||||||
|
newBalance = decay.balance
|
||||||
}
|
}
|
||||||
|
newBalance = newBalance.add(contributionLink.amount.toString())
|
||||||
|
|
||||||
|
const transaction = new DbTransaction()
|
||||||
|
transaction.typeId = TransactionTypeId.CREATION
|
||||||
|
transaction.memo = contribution.memo
|
||||||
|
transaction.userId = contribution.userId
|
||||||
|
transaction.previous = lastTransaction ? lastTransaction.id : null
|
||||||
|
transaction.amount = contribution.amount
|
||||||
|
transaction.creationDate = contribution.contributionDate
|
||||||
|
transaction.balance = newBalance
|
||||||
|
transaction.balanceDate = now
|
||||||
|
transaction.decay = decay ? decay.decay : new Decimal(0)
|
||||||
|
transaction.decayStart = decay ? decay.start : null
|
||||||
|
await queryRunner.manager.insert(DbTransaction, transaction)
|
||||||
|
|
||||||
|
contribution.confirmedAt = now
|
||||||
|
contribution.transactionId = transaction.id
|
||||||
|
await queryRunner.manager.update(DbContribution, { id: contribution.id }, contribution)
|
||||||
|
|
||||||
|
await queryRunner.commitTransaction()
|
||||||
|
logger.info('creation from contribution link commited successfuly.')
|
||||||
|
} catch (e) {
|
||||||
|
await queryRunner.rollbackTransaction()
|
||||||
|
logger.error(`Creation from contribution link was not successful: ${e}`)
|
||||||
|
throw new Error(`Creation from contribution link was not successful. ${e}`)
|
||||||
|
} finally {
|
||||||
|
await queryRunner.release()
|
||||||
}
|
}
|
||||||
|
|
||||||
const creations = await getUserCreation(user.id, clientTimezoneOffset)
|
|
||||||
logger.info('open creations', creations)
|
|
||||||
validateContribution(creations, contributionLink.amount, now, clientTimezoneOffset)
|
|
||||||
const contribution = new DbContribution()
|
|
||||||
contribution.userId = user.id
|
|
||||||
contribution.createdAt = now
|
|
||||||
contribution.contributionDate = now
|
|
||||||
contribution.memo = contributionLink.memo
|
|
||||||
contribution.amount = contributionLink.amount
|
|
||||||
contribution.contributionLinkId = contributionLink.id
|
|
||||||
contribution.contributionType = ContributionType.LINK
|
|
||||||
contribution.contributionStatus = ContributionStatus.CONFIRMED
|
|
||||||
|
|
||||||
await queryRunner.manager.insert(DbContribution, contribution)
|
|
||||||
|
|
||||||
const lastTransaction = await queryRunner.manager
|
|
||||||
.createQueryBuilder()
|
|
||||||
.select('transaction')
|
|
||||||
.from(DbTransaction, 'transaction')
|
|
||||||
.where('transaction.userId = :id', { id: user.id })
|
|
||||||
.orderBy('transaction.id', 'DESC')
|
|
||||||
.getOne()
|
|
||||||
let newBalance = new Decimal(0)
|
|
||||||
|
|
||||||
let decay: Decay | null = null
|
|
||||||
if (lastTransaction) {
|
|
||||||
decay = calculateDecay(lastTransaction.balance, lastTransaction.balanceDate, now)
|
|
||||||
newBalance = decay.balance
|
|
||||||
}
|
|
||||||
newBalance = newBalance.add(contributionLink.amount.toString())
|
|
||||||
|
|
||||||
const transaction = new DbTransaction()
|
|
||||||
transaction.typeId = TransactionTypeId.CREATION
|
|
||||||
transaction.memo = contribution.memo
|
|
||||||
transaction.userId = contribution.userId
|
|
||||||
transaction.previous = lastTransaction ? lastTransaction.id : null
|
|
||||||
transaction.amount = contribution.amount
|
|
||||||
transaction.creationDate = contribution.contributionDate
|
|
||||||
transaction.balance = newBalance
|
|
||||||
transaction.balanceDate = now
|
|
||||||
transaction.decay = decay ? decay.decay : new Decimal(0)
|
|
||||||
transaction.decayStart = decay ? decay.start : null
|
|
||||||
await queryRunner.manager.insert(DbTransaction, transaction)
|
|
||||||
|
|
||||||
contribution.confirmedAt = now
|
|
||||||
contribution.transactionId = transaction.id
|
|
||||||
await queryRunner.manager.update(DbContribution, { id: contribution.id }, contribution)
|
|
||||||
|
|
||||||
await queryRunner.commitTransaction()
|
|
||||||
logger.info('creation from contribution link commited successfuly.')
|
|
||||||
} catch (e) {
|
|
||||||
await queryRunner.rollbackTransaction()
|
|
||||||
logger.error(`Creation from contribution link was not successful: ${e}`)
|
|
||||||
throw new Error(`Creation from contribution link was not successful. ${e}`)
|
|
||||||
} finally {
|
} finally {
|
||||||
await queryRunner.release()
|
|
||||||
releaseLock()
|
releaseLock()
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
|
|||||||
@ -45,29 +45,28 @@ export const executeTransaction = async (
|
|||||||
recipient: dbUser,
|
recipient: dbUser,
|
||||||
transactionLink?: dbTransactionLink | null,
|
transactionLink?: dbTransactionLink | null,
|
||||||
): Promise<boolean> => {
|
): Promise<boolean> => {
|
||||||
logger.info(
|
|
||||||
`executeTransaction(amount=${amount}, memo=${memo}, sender=${sender}, recipient=${recipient})...`,
|
|
||||||
)
|
|
||||||
|
|
||||||
if (sender.id === recipient.id) {
|
|
||||||
logger.error(`Sender and Recipient are the same.`)
|
|
||||||
throw new Error('Sender and Recipient are the same.')
|
|
||||||
}
|
|
||||||
|
|
||||||
if (memo.length > MEMO_MAX_CHARS) {
|
|
||||||
logger.error(`memo text is too long: memo.length=${memo.length} > ${MEMO_MAX_CHARS}`)
|
|
||||||
throw new Error(`memo text is too long (${MEMO_MAX_CHARS} characters maximum)`)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (memo.length < MEMO_MIN_CHARS) {
|
|
||||||
logger.error(`memo text is too short: memo.length=${memo.length} < ${MEMO_MIN_CHARS}`)
|
|
||||||
throw new Error(`memo text is too short (${MEMO_MIN_CHARS} characters minimum)`)
|
|
||||||
}
|
|
||||||
|
|
||||||
// acquire lock
|
// acquire lock
|
||||||
const releaseLock = await TRANSACTIONS_LOCK.acquire()
|
const releaseLock = await TRANSACTIONS_LOCK.acquire()
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
logger.info(
|
||||||
|
`executeTransaction(amount=${amount}, memo=${memo}, sender=${sender}, recipient=${recipient})...`,
|
||||||
|
)
|
||||||
|
|
||||||
|
if (sender.id === recipient.id) {
|
||||||
|
logger.error(`Sender and Recipient are the same.`)
|
||||||
|
throw new Error('Sender and Recipient are the same.')
|
||||||
|
}
|
||||||
|
|
||||||
|
if (memo.length > MEMO_MAX_CHARS) {
|
||||||
|
logger.error(`memo text is too long: memo.length=${memo.length} > ${MEMO_MAX_CHARS}`)
|
||||||
|
throw new Error(`memo text is too long (${MEMO_MAX_CHARS} characters maximum)`)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (memo.length < MEMO_MIN_CHARS) {
|
||||||
|
logger.error(`memo text is too short: memo.length=${memo.length} < ${MEMO_MIN_CHARS}`)
|
||||||
|
throw new Error(`memo text is too short (${MEMO_MIN_CHARS} characters minimum)`)
|
||||||
|
}
|
||||||
|
|
||||||
// validate amount
|
// validate amount
|
||||||
const receivedCallDate = new Date()
|
const receivedCallDate = new Date()
|
||||||
const sendBalance = await calculateBalance(
|
const sendBalance = await calculateBalance(
|
||||||
@ -187,10 +186,10 @@ export const executeTransaction = async (
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
logger.info(`finished executeTransaction successfully`)
|
logger.info(`finished executeTransaction successfully`)
|
||||||
return true
|
|
||||||
} finally {
|
} finally {
|
||||||
releaseLock()
|
releaseLock()
|
||||||
}
|
}
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
@Resolver()
|
@Resolver()
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "gradido-database",
|
"name": "gradido-database",
|
||||||
"version": "1.16.0",
|
"version": "1.17.1",
|
||||||
"description": "Gradido Database Tool to execute database migrations",
|
"description": "Gradido Database Tool to execute database migrations",
|
||||||
"main": "src/index.ts",
|
"main": "src/index.ts",
|
||||||
"repository": "https://github.com/gradido/gradido/database",
|
"repository": "https://github.com/gradido/gradido/database",
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "bootstrap-vue-gradido-wallet",
|
"name": "bootstrap-vue-gradido-wallet",
|
||||||
"version": "1.16.0",
|
"version": "1.17.1",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "node run/server.js",
|
"start": "node run/server.js",
|
||||||
|
|||||||
@ -30,7 +30,7 @@ export default {
|
|||||||
font-family: 'WorkSans', sans-serif !important;
|
font-family: 'WorkSans', sans-serif !important;
|
||||||
}
|
}
|
||||||
.appContent {
|
.appContent {
|
||||||
min-width: 360px;
|
min-width: 330px;
|
||||||
max-width: 1320px;
|
max-width: 1320px;
|
||||||
margin-right: auto;
|
margin-right: auto;
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
|
|||||||
@ -18,7 +18,7 @@
|
|||||||
"date": "01 janvier 2023",
|
"date": "01 janvier 2023",
|
||||||
"text": "Compte Gradido 2023 : nouveau design et communautés décentralisées",
|
"text": "Compte Gradido 2023 : nouveau design et communautés décentralisées",
|
||||||
"url": "https://gradido.net/fr/gradido-konto-2023-neues-design-und-dezentrale-communities/",
|
"url": "https://gradido.net/fr/gradido-konto-2023-neues-design-und-dezentrale-communities/",
|
||||||
"extra": "Ce sont souvent les personnes les plus discrètes qui créent silencieusement, avec application et passion, les bases de grands développements. Notre site Développeur ont effectué ces derniers mois un travail préparatoire formidable qui sera mis à profit en 2023."
|
"extra": "Ce sont souvent les personnes les plus discrètes qui créent silencieusement, avec application et passion, les bases de grands développements. Nos développeurs ont effectués ces derniers mois un travail préparatoire formidable qui sera mis à profit en 2023."
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"locale": "es",
|
"locale": "es",
|
||||||
|
|||||||
@ -11,7 +11,7 @@ body {
|
|||||||
|
|
||||||
.bg-gradient {
|
.bg-gradient {
|
||||||
background: rgb(4 112 6);
|
background: rgb(4 112 6);
|
||||||
background: linear-gradient(90deg, rgb(4 112 6 / 100%) 73%, rgb(197 141 56 / 100%) 100%);
|
background: linear-gradient(90deg, rgb(4 112 6 / 100%) 22%, rgb(197 141 56 / 100%) 98%);
|
||||||
color: white;
|
color: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -53,6 +53,7 @@ export default {
|
|||||||
|
|
||||||
.auth-header {
|
.auth-header {
|
||||||
font-family: 'Open Sans', sans-serif !important;
|
font-family: 'Open Sans', sans-serif !important;
|
||||||
|
height: 150px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sheet-img {
|
.sheet-img {
|
||||||
@ -61,6 +62,17 @@ export default {
|
|||||||
max-width: 64%;
|
max-width: 64%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@media screen and (max-width: 1024px) {
|
||||||
|
.auth-header {
|
||||||
|
height: 100px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (max-width: 768px) {
|
||||||
|
.auth-header {
|
||||||
|
height: 70px;
|
||||||
|
}
|
||||||
|
}
|
||||||
@media screen and (max-width: 450px) {
|
@media screen and (max-width: 450px) {
|
||||||
.sheet-img {
|
.sheet-img {
|
||||||
top: -15px;
|
top: -15px;
|
||||||
|
|||||||
@ -1,17 +1,31 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="clipboard-copy">
|
<div class="clipboard-copy">
|
||||||
<div v-if="canCopyLink" size="lg" class="mb-5">
|
<div v-if="canCopyLink" class="mb-5">
|
||||||
<div class="d-flex">
|
<div>
|
||||||
<div>
|
<label>{{ $t('gdd_per_link.copy-link') }}</label>
|
||||||
<label>{{ $t('gdd_per_link.copy-link') }}</label>
|
<div
|
||||||
<div class="pointer text-center bg-secondary gradido-border-radius p-4" @click="copyLink">
|
class="pointer text-center bg-secondary gradido-border-radius p-3"
|
||||||
{{ link }}
|
@click="copyLink"
|
||||||
|
data-test="copyLink"
|
||||||
|
>
|
||||||
|
{{ link }}
|
||||||
|
<div>
|
||||||
|
<b-button class="p-4">
|
||||||
|
<b-icon icon="link45deg"></b-icon>
|
||||||
|
</b-button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="ml-5">
|
</div>
|
||||||
<label>{{ $t('gdd_per_link.copy-link-with-text') }}</label>
|
<div class="mt-5">
|
||||||
|
<label>{{ $t('gdd_per_link.copy-link-with-text') }}</label>
|
||||||
|
<div
|
||||||
|
class="pointer text-center bg-secondary gradido-border-radius p-3"
|
||||||
|
data-test="copyLinkWithText"
|
||||||
|
@click="copyLinkWithText"
|
||||||
|
>
|
||||||
|
{{ linkText }}
|
||||||
<div>
|
<div>
|
||||||
<b-button @click="copyLinkWithText" class="p-4">
|
<b-button class="p-4">
|
||||||
<b-icon icon="link45deg"></b-icon>
|
<b-icon icon="link45deg"></b-icon>
|
||||||
</b-button>
|
</b-button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -12,6 +12,7 @@ describe('ContributionForm', () => {
|
|||||||
date: '',
|
date: '',
|
||||||
memo: '',
|
memo: '',
|
||||||
amount: '',
|
amount: '',
|
||||||
|
hours: 0,
|
||||||
},
|
},
|
||||||
isThisMonth: true,
|
isThisMonth: true,
|
||||||
minimalDate: new Date(),
|
minimalDate: new Date(),
|
||||||
@ -22,6 +23,7 @@ describe('ContributionForm', () => {
|
|||||||
const mocks = {
|
const mocks = {
|
||||||
$t: jest.fn((t) => t),
|
$t: jest.fn((t) => t),
|
||||||
$d: jest.fn((d) => d),
|
$d: jest.fn((d) => d),
|
||||||
|
$n: jest.fn((n) => n),
|
||||||
$store: {
|
$store: {
|
||||||
state: {
|
state: {
|
||||||
creation: ['1000', '1000', '1000'],
|
creation: ['1000', '1000', '1000'],
|
||||||
@ -375,6 +377,7 @@ describe('ContributionForm', () => {
|
|||||||
date: now,
|
date: now,
|
||||||
memo: 'Mein Beitrag zur Gemeinschaft für diesen Monat ...',
|
memo: 'Mein Beitrag zur Gemeinschaft für diesen Monat ...',
|
||||||
amount: '200',
|
amount: '200',
|
||||||
|
hours: 0,
|
||||||
},
|
},
|
||||||
]),
|
]),
|
||||||
]),
|
]),
|
||||||
|
|||||||
@ -3,13 +3,12 @@
|
|||||||
<b-form
|
<b-form
|
||||||
ref="form"
|
ref="form"
|
||||||
@submit.prevent="submit"
|
@submit.prevent="submit"
|
||||||
class="border p-3 bg-white appBoxShadow gradido-border-radius"
|
class="p-3 bg-white appBoxShadow gradido-border-radius"
|
||||||
>
|
>
|
||||||
<label>{{ $t('contribution.selectDate') }}</label>
|
<label>{{ $t('contribution.selectDate') }}</label>
|
||||||
<b-form-datepicker
|
<b-form-datepicker
|
||||||
id="contribution-date"
|
id="contribution-date"
|
||||||
v-model="form.date"
|
v-model="form.date"
|
||||||
size="lg"
|
|
||||||
:locale="$i18n.locale"
|
:locale="$i18n.locale"
|
||||||
:max="maximalDate"
|
:max="maximalDate"
|
||||||
:min="minimalDate"
|
:min="minimalDate"
|
||||||
@ -18,44 +17,44 @@
|
|||||||
:label-no-date-selected="$t('contribution.noDateSelected')"
|
:label-no-date-selected="$t('contribution.noDateSelected')"
|
||||||
required
|
required
|
||||||
:disabled="this.form.id !== null"
|
:disabled="this.form.id !== null"
|
||||||
|
:no-flip="true"
|
||||||
>
|
>
|
||||||
<template #nav-prev-year><span></span></template>
|
<template #nav-prev-year><span></span></template>
|
||||||
<template #nav-next-year><span></span></template>
|
<template #nav-next-year><span></span></template>
|
||||||
</b-form-datepicker>
|
</b-form-datepicker>
|
||||||
<div v-if="validMaxGDD > 0">
|
|
||||||
<input-textarea
|
<input-textarea
|
||||||
id="contribution-memo"
|
id="contribution-memo"
|
||||||
v-model="form.memo"
|
v-model="form.memo"
|
||||||
:name="$t('form.message')"
|
:name="$t('form.message')"
|
||||||
:label="$t('contribution.activity')"
|
:label="$t('contribution.activity')"
|
||||||
:placeholder="$t('contribution.yourActivity')"
|
:placeholder="$t('contribution.yourActivity')"
|
||||||
:rules="{ required: true, min: 5, max: 255 }"
|
:rules="{ required: true, min: 5, max: 255 }"
|
||||||
/>
|
/>
|
||||||
<input-hour
|
<input-hour
|
||||||
v-model="form.hours"
|
v-model="form.hours"
|
||||||
:name="$t('form.hours')"
|
:name="$t('form.hours')"
|
||||||
:label="$t('form.hours')"
|
:label="$t('form.hours')"
|
||||||
placeholder="0.5"
|
placeholder="0.25"
|
||||||
:rules="{
|
:rules="{
|
||||||
required: true,
|
required: true,
|
||||||
min: 0.5,
|
min: 0.25,
|
||||||
max: validMaxTime,
|
max: validMaxTime,
|
||||||
gddCreationTime: [0.5, validMaxTime],
|
gddCreationTime: [0.25, validMaxTime],
|
||||||
}"
|
}"
|
||||||
:validMaxTime="validMaxTime"
|
:validMaxTime="validMaxTime"
|
||||||
@updateAmount="updateAmount"
|
@updateAmount="updateAmount"
|
||||||
></input-hour>
|
></input-hour>
|
||||||
<input-amount
|
<input-amount
|
||||||
id="contribution-amount"
|
id="contribution-amount"
|
||||||
v-model="form.amount"
|
v-model="form.amount"
|
||||||
:name="$t('form.amount')"
|
:name="$t('form.amount')"
|
||||||
:label="$t('form.amount')"
|
:label="$t('form.amount')"
|
||||||
placeholder="20"
|
placeholder="20"
|
||||||
:rules="{ required: true, gddSendAmount: [20, validMaxGDD] }"
|
:rules="{ required: true, gddSendAmount: [20, validMaxGDD] }"
|
||||||
typ="ContributionForm"
|
typ="ContributionForm"
|
||||||
></input-amount>
|
></input-amount>
|
||||||
</div>
|
|
||||||
<div v-else class="mb-5">{{ $t('contribution.exhausted') }}</div>
|
|
||||||
<b-row class="mt-5">
|
<b-row class="mt-5">
|
||||||
<b-col>
|
<b-col>
|
||||||
<b-button type="reset" variant="secondary" @click="reset" data-test="button-cancel">
|
<b-button type="reset" variant="secondary" @click="reset" data-test="button-cancel">
|
||||||
@ -111,7 +110,7 @@ export default {
|
|||||||
this.form.id = null
|
this.form.id = null
|
||||||
this.form.date = ''
|
this.form.date = ''
|
||||||
this.form.memo = ''
|
this.form.memo = ''
|
||||||
this.form.hours = 0.0
|
this.form.hours = 0
|
||||||
this.form.amount = ''
|
this.form.amount = ''
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@ -48,7 +48,7 @@ describe('ContributionListItem', () => {
|
|||||||
|
|
||||||
it('is x-circle when deletedAt is present', async () => {
|
it('is x-circle when deletedAt is present', async () => {
|
||||||
await wrapper.setProps({ deletedAt: new Date().toISOString() })
|
await wrapper.setProps({ deletedAt: new Date().toISOString() })
|
||||||
expect(wrapper.vm.icon).toBe('x-circle')
|
expect(wrapper.vm.icon).toBe('trash')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('is check when confirmedAt is present', async () => {
|
it('is check when confirmedAt is present', async () => {
|
||||||
|
|||||||
@ -16,21 +16,27 @@
|
|||||||
<b-avatar v-else :icon="icon" :variant="variant" size="3em"></b-avatar>
|
<b-avatar v-else :icon="icon" :variant="variant" size="3em"></b-avatar>
|
||||||
</b-col>
|
</b-col>
|
||||||
<b-col>
|
<b-col>
|
||||||
<div v-if="firstName" class="mr-3 font-weight-bold">{{ firstName }} {{ lastName }}</div>
|
<div v-if="firstName" class="mr-3 font-weight-bold">
|
||||||
|
{{ firstName }} {{ lastName }}
|
||||||
|
<b-icon :icon="icon" :variant="variant"></b-icon>
|
||||||
|
</div>
|
||||||
<div class="small">
|
<div class="small">
|
||||||
{{ $d(new Date(contributionDate), 'monthAndYear') }}
|
{{ $d(new Date(contributionDate), 'monthAndYear') }}
|
||||||
</div>
|
</div>
|
||||||
<div class="mt-3 font-weight-bold">{{ $t('contributionText') }}</div>
|
<div class="mt-3 font-weight-bold">{{ $t('contributionText') }}</div>
|
||||||
<div class="mb-3">{{ memo }}</div>
|
<div class="mb-3 text-break word-break">{{ memo }}</div>
|
||||||
<div v-if="state === 'IN_PROGRESS'" class="text-205">
|
<div v-if="state === 'IN_PROGRESS'" class="text-205">
|
||||||
{{ $t('contribution.alert.answerQuestion') }}
|
{{ $t('contribution.alert.answerQuestion') }}
|
||||||
</div>
|
</div>
|
||||||
</b-col>
|
</b-col>
|
||||||
<b-col cols="12" lg="3" offset="3" offset-md="0" offset-lg="0">
|
<b-col cols="9" lg="3" offset="3" offset-md="0" offset-lg="0">
|
||||||
<div class="small">
|
<div class="small">
|
||||||
{{ $t('creation') }} {{ $t('(') }}{{ amount / 20 }} {{ $t('h') }}{{ $t(')') }}
|
{{ $t('creation') }} {{ $t('(') }}{{ amount / 20 }} {{ $t('h') }}{{ $t(')') }}
|
||||||
</div>
|
</div>
|
||||||
<div class="font-weight-bold">{{ amount | GDD }}</div>
|
<div v-if="state === 'DELETED'" class="small">
|
||||||
|
{{ $t('contribution.deleted') }}
|
||||||
|
</div>
|
||||||
|
<div v-else class="font-weight-bold">{{ amount | GDD }}</div>
|
||||||
</b-col>
|
</b-col>
|
||||||
<b-col cols="12" md="1" lg="1" class="text-right align-items-center">
|
<b-col cols="12" md="1" lg="1" class="text-right align-items-center">
|
||||||
<div v-if="messagesCount > 0" @click="visible = !visible">
|
<div v-if="messagesCount > 0" @click="visible = !visible">
|
||||||
@ -168,7 +174,7 @@ export default {
|
|||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
icon() {
|
icon() {
|
||||||
if (this.deletedAt) return 'x-circle'
|
if (this.deletedAt) return 'trash'
|
||||||
if (this.confirmedAt) return 'check'
|
if (this.confirmedAt) return 'check'
|
||||||
if (this.state === 'IN_PROGRESS') return 'question-circle'
|
if (this.state === 'IN_PROGRESS') return 'question-circle'
|
||||||
return 'bell-fill'
|
return 'bell-fill'
|
||||||
|
|||||||
@ -10,6 +10,12 @@ const mocks = {
|
|||||||
$tc: jest.fn((tc) => tc),
|
$tc: jest.fn((tc) => tc),
|
||||||
$t: jest.fn((t) => t),
|
$t: jest.fn((t) => t),
|
||||||
$d: jest.fn((d) => d),
|
$d: jest.fn((d) => d),
|
||||||
|
$store: {
|
||||||
|
state: {
|
||||||
|
firstName: 'Bibi',
|
||||||
|
lastName: 'Bloxberg',
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
const propsData = {
|
const propsData = {
|
||||||
|
|||||||
@ -35,12 +35,15 @@
|
|||||||
<b-col offset="2">{{ $t('form.new_balance') }}</b-col>
|
<b-col offset="2">{{ $t('form.new_balance') }}</b-col>
|
||||||
<b-col>{{ (balance - amount) | GDD }}</b-col>
|
<b-col>{{ (balance - amount) | GDD }}</b-col>
|
||||||
</b-row>
|
</b-row>
|
||||||
<b-row class="mt-5 p-5">
|
<b-row class="mt-5">
|
||||||
<b-col>
|
<b-col cols="12" md="6" lg="6">
|
||||||
<b-button @click="$emit('on-back')">{{ $t('back') }}</b-button>
|
<b-button block @click="$emit('on-back')" class="mb-3 mb-md-0 mb-lg-0">
|
||||||
|
{{ $t('back') }}
|
||||||
|
</b-button>
|
||||||
</b-col>
|
</b-col>
|
||||||
<b-col class="text-right">
|
<b-col cols="12" md="6" lg="6" class="text-lg-right">
|
||||||
<b-button
|
<b-button
|
||||||
|
block
|
||||||
class="send-button"
|
class="send-button"
|
||||||
variant="gradido"
|
variant="gradido"
|
||||||
:disabled="disabled"
|
:disabled="disabled"
|
||||||
|
|||||||
@ -17,7 +17,7 @@
|
|||||||
</b-col>
|
</b-col>
|
||||||
</b-row>
|
</b-row>
|
||||||
|
|
||||||
<b-row class="mt-5 pr-3 text-color-gdd-yellow h3">
|
<b-row class="mt-5 text-color-gdd-yellow h3">
|
||||||
<b-col cols="2" class="text-right">
|
<b-col cols="2" class="text-right">
|
||||||
<b-icon class="text-color-gdd-yellow" icon="droplet-half"></b-icon>
|
<b-icon class="text-color-gdd-yellow" icon="droplet-half"></b-icon>
|
||||||
</b-col>
|
</b-col>
|
||||||
@ -39,12 +39,15 @@
|
|||||||
<b-col offset="2">{{ $t('form.new_balance') }}</b-col>
|
<b-col offset="2">{{ $t('form.new_balance') }}</b-col>
|
||||||
<b-col>{{ (balance - amount) | GDD }}</b-col>
|
<b-col>{{ (balance - amount) | GDD }}</b-col>
|
||||||
</b-row>
|
</b-row>
|
||||||
<b-row class="mt-5 p-5">
|
<b-row class="mt-5">
|
||||||
<b-col>
|
<b-col cols="12" md="6" lg="6">
|
||||||
<b-button @click="$emit('on-back')">{{ $t('back') }}</b-button>
|
<b-button block @click="$emit('on-back')" class="mb-3 mb-md-0 mb-lg-0">
|
||||||
|
{{ $t('back') }}
|
||||||
|
</b-button>
|
||||||
</b-col>
|
</b-col>
|
||||||
<b-col class="text-right">
|
<b-col cols="12" md="6" lg="6" class="text-lg-right">
|
||||||
<b-button
|
<b-button
|
||||||
|
block
|
||||||
variant="gradido"
|
variant="gradido"
|
||||||
:disabled="disabled"
|
:disabled="disabled"
|
||||||
@click="$emit('send-transaction'), (disabled = true)"
|
@click="$emit('send-transaction'), (disabled = true)"
|
||||||
|
|||||||
@ -92,14 +92,20 @@
|
|||||||
<div v-if="!!isBalanceDisabled" class="text-danger mt-5">
|
<div v-if="!!isBalanceDisabled" class="text-danger mt-5">
|
||||||
{{ $t('form.no_gdd_available') }}
|
{{ $t('form.no_gdd_available') }}
|
||||||
</div>
|
</div>
|
||||||
<b-row v-else class="test-buttons mt-5">
|
<b-row v-else class="test-buttons mt-3">
|
||||||
<b-col>
|
<b-col cols="12" md="6" lg="6">
|
||||||
<b-button type="reset" variant="secondary" @click="onReset">
|
<b-button
|
||||||
|
block
|
||||||
|
type="reset"
|
||||||
|
variant="secondary"
|
||||||
|
@click="onReset"
|
||||||
|
class="mb-3 mb-md-0 mb-lg-0"
|
||||||
|
>
|
||||||
{{ $t('form.reset') }}
|
{{ $t('form.reset') }}
|
||||||
</b-button>
|
</b-button>
|
||||||
</b-col>
|
</b-col>
|
||||||
<b-col class="text-right">
|
<b-col cols="12" md="6" lg="6" class="text-lg-right">
|
||||||
<b-button type="submit" variant="gradido">
|
<b-button block type="submit" variant="gradido">
|
||||||
{{ $t('form.check_now') }}
|
{{ $t('form.check_now') }}
|
||||||
</b-button>
|
</b-button>
|
||||||
</b-col>
|
</b-col>
|
||||||
|
|||||||
@ -7,6 +7,7 @@
|
|||||||
:memo="memo"
|
:memo="memo"
|
||||||
:validUntil="validUntil"
|
:validUntil="validUntil"
|
||||||
></clipboard-copy>
|
></clipboard-copy>
|
||||||
|
<label>{{ $t('qrCode') }}</label>
|
||||||
<div class="text-center">
|
<div class="text-center">
|
||||||
<div><figure-qr-code :link="link" /></div>
|
<div><figure-qr-code :link="link" /></div>
|
||||||
<div>
|
<div>
|
||||||
|
|||||||
@ -26,45 +26,46 @@
|
|||||||
</template>
|
</template>
|
||||||
</transaction-list-item>
|
</transaction-list-item>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="transactionCount > 0" class="h4 m-3">{{ $t('lastMonth') }}</div>
|
<div class="mt-3">
|
||||||
<div v-for="({ id, typeId }, index) in transactions" :key="`l2-` + id">
|
<div v-for="({ id, typeId }, index) in transactions" :key="`l2-` + id">
|
||||||
<transaction-list-item
|
<transaction-list-item
|
||||||
v-if="typeId !== 'DECAY'"
|
v-if="typeId !== 'DECAY'"
|
||||||
:typeId="typeId"
|
:typeId="typeId"
|
||||||
class="pointer mb-4 bg-white appBoxShadow gradido-border-radius p-3 test-list-group-item"
|
class="pointer mb-3 bg-white appBoxShadow gradido-border-radius p-3 test-list-group-item"
|
||||||
>
|
>
|
||||||
<template #SEND>
|
<template #SEND>
|
||||||
<transaction-send
|
<transaction-send
|
||||||
v-bind="transactions[index]"
|
v-bind="transactions[index]"
|
||||||
:previousBookedBalance="previousBookedBalance(index)"
|
:previousBookedBalance="previousBookedBalance(index)"
|
||||||
v-on="$listeners"
|
v-on="$listeners"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template #RECEIVE>
|
<template #RECEIVE>
|
||||||
<transaction-receive
|
<transaction-receive
|
||||||
v-bind="transactions[index]"
|
v-bind="transactions[index]"
|
||||||
:previousBookedBalance="previousBookedBalance(index)"
|
:previousBookedBalance="previousBookedBalance(index)"
|
||||||
v-on="$listeners"
|
v-on="$listeners"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template #CREATION>
|
<template #CREATION>
|
||||||
<transaction-creation
|
<transaction-creation
|
||||||
v-bind="transactions[index]"
|
v-bind="transactions[index]"
|
||||||
:previousBookedBalance="previousBookedBalance(index)"
|
:previousBookedBalance="previousBookedBalance(index)"
|
||||||
v-on="$listeners"
|
v-on="$listeners"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template #LINK_SUMMARY>
|
<template #LINK_SUMMARY>
|
||||||
<transaction-link-summary
|
<transaction-link-summary
|
||||||
v-bind="transactions[index]"
|
v-bind="transactions[index]"
|
||||||
:transactionLinkCount="transactionLinkCount"
|
:transactionLinkCount="transactionLinkCount"
|
||||||
@update-transactions="updateTransactions"
|
@update-transactions="updateTransactions"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
</transaction-list-item>
|
</transaction-list-item>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<b-pagination
|
<b-pagination
|
||||||
|
|||||||
@ -9,10 +9,10 @@ describe('InputAmount', () => {
|
|||||||
|
|
||||||
const mocks = {
|
const mocks = {
|
||||||
$t: jest.fn((t) => t),
|
$t: jest.fn((t) => t),
|
||||||
|
$n: jest.fn((n) => n),
|
||||||
$i18n: {
|
$i18n: {
|
||||||
locale: jest.fn(() => 'en'),
|
locale: jest.fn(() => 'en'),
|
||||||
},
|
},
|
||||||
$n: jest.fn((n) => String(n)),
|
|
||||||
$route: {
|
$route: {
|
||||||
params: {},
|
params: {},
|
||||||
},
|
},
|
||||||
@ -46,13 +46,14 @@ describe('InputAmount', () => {
|
|||||||
|
|
||||||
describe('amount normalization', () => {
|
describe('amount normalization', () => {
|
||||||
describe('if invalid', () => {
|
describe('if invalid', () => {
|
||||||
beforeEach(() => {
|
beforeEach(async () => {
|
||||||
|
await wrapper.setProps({ value: '12m34' })
|
||||||
valid = false
|
valid = false
|
||||||
})
|
})
|
||||||
|
|
||||||
it('is not normalized', () => {
|
it('is not normalized', () => {
|
||||||
wrapper.vm.normalizeAmount(valid)
|
wrapper.vm.normalizeAmount(false)
|
||||||
expect(wrapper.vm.amountValue).toBe(0.0)
|
expect(wrapper.vm.currentValue).toBe('12m34')
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -97,13 +98,14 @@ describe('InputAmount', () => {
|
|||||||
|
|
||||||
describe('amount normalization', () => {
|
describe('amount normalization', () => {
|
||||||
describe('if invalid', () => {
|
describe('if invalid', () => {
|
||||||
beforeEach(() => {
|
beforeEach(async () => {
|
||||||
|
await wrapper.setProps({ value: '12m34' })
|
||||||
valid = false
|
valid = false
|
||||||
})
|
})
|
||||||
|
|
||||||
it('is not normalized', () => {
|
it('is not normalized', () => {
|
||||||
wrapper.vm.normalizeAmount(valid)
|
wrapper.vm.normalizeAmount(valid)
|
||||||
expect(wrapper.vm.amountValue).toBe(0.0)
|
expect(wrapper.vm.currentValue).toBe('12m34')
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@ -20,7 +20,7 @@
|
|||||||
trim
|
trim
|
||||||
v-focus="amountFocused"
|
v-focus="amountFocused"
|
||||||
@focus="amountFocused = true"
|
@focus="amountFocused = true"
|
||||||
@blur="normalizeAmount(true)"
|
@blur="normalizeAmount(valid)"
|
||||||
:disabled="disabled"
|
:disabled="disabled"
|
||||||
autocomplete="off"
|
autocomplete="off"
|
||||||
></b-form-input>
|
></b-form-input>
|
||||||
@ -90,5 +90,8 @@ export default {
|
|||||||
this.currentValue = this.$n(this.amountValue, 'ungroupedDecimal')
|
this.currentValue = this.$n(this.amountValue, 'ungroupedDecimal')
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
mounted() {
|
||||||
|
if (this.value !== '') this.normalizeAmount(true)
|
||||||
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -74,7 +74,7 @@ describe('InputHour', () => {
|
|||||||
it('emits input with new value', async () => {
|
it('emits input with new value', async () => {
|
||||||
await wrapper.find('input').setValue('12')
|
await wrapper.find('input').setValue('12')
|
||||||
expect(wrapper.emitted('input')).toBeTruthy()
|
expect(wrapper.emitted('input')).toBeTruthy()
|
||||||
expect(wrapper.emitted('input')).toEqual([['12']])
|
expect(wrapper.emitted('input')).toEqual([[12]])
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@ -15,7 +15,7 @@
|
|||||||
:placeholder="placeholder"
|
:placeholder="placeholder"
|
||||||
type="number"
|
type="number"
|
||||||
:state="validated ? valid : false"
|
:state="validated ? valid : false"
|
||||||
step="0.5"
|
step="0.25"
|
||||||
min="0"
|
min="0"
|
||||||
:max="validMaxTime"
|
:max="validMaxTime"
|
||||||
class="bg-248"
|
class="bg-248"
|
||||||
@ -32,11 +32,11 @@ export default {
|
|||||||
type: Object,
|
type: Object,
|
||||||
default: () => {},
|
default: () => {},
|
||||||
},
|
},
|
||||||
name: { type: String, required: true, default: 'Time' },
|
name: { type: String, required: true },
|
||||||
label: { type: String, required: true, default: 'Time' },
|
label: { type: String, required: true },
|
||||||
placeholder: { type: String, required: true, default: 'Time' },
|
placeholder: { type: String, required: true },
|
||||||
value: { type: Number, required: true, default: 0 },
|
value: { type: Number, required: true, default: 0 },
|
||||||
validMaxTime: { type: Number, required: true, default: 0 },
|
validMaxTime: { type: Number, required: true },
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
@ -50,7 +50,7 @@ export default {
|
|||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
currentValue() {
|
currentValue() {
|
||||||
this.$emit('input', this.currentValue)
|
this.$emit('input', Number(this.currentValue))
|
||||||
},
|
},
|
||||||
value() {
|
value() {
|
||||||
if (this.value !== this.currentValue) this.currentValue = this.value
|
if (this.value !== this.currentValue) this.currentValue = this.value
|
||||||
|
|||||||
@ -18,6 +18,7 @@
|
|||||||
rows="4"
|
rows="4"
|
||||||
max-rows="4"
|
max-rows="4"
|
||||||
:disabled="disabled"
|
:disabled="disabled"
|
||||||
|
no-resize
|
||||||
></b-form-textarea>
|
></b-form-textarea>
|
||||||
<b-form-invalid-feedback v-bind="ariaMsg">
|
<b-form-invalid-feedback v-bind="ariaMsg">
|
||||||
{{ errors[0] }}
|
{{ errors[0] }}
|
||||||
|
|||||||
@ -1,64 +1,49 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="navbar-component position-sticky">
|
<div class="navbar-component">
|
||||||
<b-navbar toggleable="lg" class="pr-4">
|
<div class="navbar-element">
|
||||||
<b-navbar-brand>
|
<b-navbar toggleable="lg" class="pr-4">
|
||||||
<b-img
|
<b-navbar-brand>
|
||||||
class="imgLogo mt-lg--2 mt-3 mb-3 d-none d-lg-block zindex10"
|
<b-img
|
||||||
:src="logo"
|
class="imgLogo mt-lg--2 mt-3 mb-3 d-none d-lg-block zindex10"
|
||||||
width=""
|
:src="logo"
|
||||||
alt="..."
|
width=""
|
||||||
/>
|
alt="..."
|
||||||
<b-button v-b-toggle.sidebar-mobile class="d-block d-lg-none">
|
/>
|
||||||
<span class="navbar-toggler-icon"></span>
|
<div v-b-toggle.sidebar-mobile variant="link" class="d-block d-lg-none">
|
||||||
</b-button>
|
<span class="navbar-toggler-icon h2"></span>
|
||||||
</b-navbar-brand>
|
|
||||||
|
|
||||||
<router-link to="/settings" class="d-block d-lg-none">
|
|
||||||
<div class="d-flex align-items-center">
|
|
||||||
<div class="mr-3">
|
|
||||||
<avatar
|
|
||||||
:username="username.username"
|
|
||||||
:initials="username.initials"
|
|
||||||
:color="'#fff'"
|
|
||||||
:size="61"
|
|
||||||
></avatar>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</b-navbar-brand>
|
||||||
</router-link>
|
|
||||||
<b-img class="sheet-img position-absolute zindex-1" :src="sheet"></b-img>
|
|
||||||
<b-collapse id="nav-collapse" is-nav class="ml-5">
|
|
||||||
<b-navbar-nav class="ml-auto" right>
|
|
||||||
<div class="mb-2">
|
|
||||||
<router-link to="/settings">
|
|
||||||
<div>
|
|
||||||
<div class="d-flex align-items-center">
|
|
||||||
<div class="mr-3">
|
|
||||||
<avatar
|
|
||||||
:username="username.username"
|
|
||||||
:initials="username.initials"
|
|
||||||
:color="'#fff'"
|
|
||||||
:size="81"
|
|
||||||
></avatar>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<div data-test="navbar-item-username">{{ username.username }}</div>
|
|
||||||
|
|
||||||
<div class="text-right" data-test="navbar-item-email">
|
<b-img class="sheet-img position-absolute zindex-1" :src="sheet"></b-img>
|
||||||
{{ $store.state.email }}
|
|
||||||
</div>
|
<b-navbar-nav class="ml-auto" right>
|
||||||
</div>
|
<router-link to="/settings">
|
||||||
|
<div class="d-flex align-items-center">
|
||||||
|
<div class="mr-3">
|
||||||
|
<avatar
|
||||||
|
:username="username.username"
|
||||||
|
:initials="username.initials"
|
||||||
|
:color="'#fff'"
|
||||||
|
:size="61"
|
||||||
|
></avatar>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div data-test="navbar-item-username">{{ username.username }}</div>
|
||||||
|
|
||||||
|
<div data-test="navbar-item-email">
|
||||||
|
{{ $store.state.email }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</router-link>
|
</div>
|
||||||
</div>
|
</router-link>
|
||||||
</b-navbar-nav>
|
</b-navbar-nav>
|
||||||
</b-collapse>
|
</b-navbar>
|
||||||
</b-navbar>
|
<!-- <div class="alertBox">
|
||||||
<!-- <div class="alertBox">
|
|
||||||
<b-alert show dismissible variant="light" class="nav-alert text-dark">
|
<b-alert show dismissible variant="light" class="nav-alert text-dark">
|
||||||
<small>{{ $t('1000thanks') }}</small>
|
<small>{{ $t('1000thanks') }}</small>
|
||||||
</b-alert>
|
</b-alert>
|
||||||
</div> -->
|
</div> -->
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -91,6 +76,10 @@ export default {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
|
.navbar-element {
|
||||||
|
position: sticky;
|
||||||
|
}
|
||||||
|
|
||||||
.auth-header {
|
.auth-header {
|
||||||
font-family: 'Open Sans', sans-serif !important;
|
font-family: 'Open Sans', sans-serif !important;
|
||||||
height: 150px;
|
height: 150px;
|
||||||
@ -126,7 +115,7 @@ button.navbar-toggler > span.navbar-toggler-icon {
|
|||||||
}
|
}
|
||||||
@media screen and (max-width: 1170px) {
|
@media screen and (max-width: 1170px) {
|
||||||
.sheet-img {
|
.sheet-img {
|
||||||
left: 40%;
|
left: 20%;
|
||||||
}
|
}
|
||||||
.alertBox {
|
.alertBox {
|
||||||
position: static;
|
position: static;
|
||||||
@ -136,10 +125,15 @@ button.navbar-toggler > span.navbar-toggler-icon {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
@media screen and (max-width: 450px) {
|
@media screen and (max-width: 450px) {
|
||||||
.sheet-img {
|
.navbar-element {
|
||||||
left: 37%;
|
|
||||||
max-width: 61%;
|
|
||||||
z-index: 1000;
|
z-index: 1000;
|
||||||
|
position: fixed;
|
||||||
|
width: 100%;
|
||||||
|
background-color: #f5f5f5e6;
|
||||||
|
}
|
||||||
|
.sheet-img {
|
||||||
|
left: 5%;
|
||||||
|
max-width: 61%;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@ -1,6 +1,11 @@
|
|||||||
<template>
|
<template>
|
||||||
<div id="component-sidebar">
|
<div id="component-sidebar">
|
||||||
<div id="side-menu" ref="sideMenu" class="gradido-border-radius appBoxShadow pt-2">
|
<div
|
||||||
|
id="side-menu"
|
||||||
|
ref="sideMenu"
|
||||||
|
class="gradido-border-radius pt-2 bg-white"
|
||||||
|
:class="shadow ? 'appBoxShadow' : ''"
|
||||||
|
>
|
||||||
<div class="mb-3 mt-3">
|
<div class="mb-3 mt-3">
|
||||||
<b-nav vertical class="w-200">
|
<b-nav vertical class="w-200">
|
||||||
<b-nav-item to="/overview" class="mb-3" active-class="activeRoute">
|
<b-nav-item to="/overview" class="mb-3" active-class="activeRoute">
|
||||||
@ -55,6 +60,9 @@
|
|||||||
<script>
|
<script>
|
||||||
export default {
|
export default {
|
||||||
name: 'Sidebar',
|
name: 'Sidebar',
|
||||||
|
props: {
|
||||||
|
shadow: { type: Boolean, required: false, default: true },
|
||||||
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<style>
|
<style>
|
||||||
|
|||||||
@ -1,23 +1,9 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<b-sidebar id="sidebar-mobile" bg-variant="f5" :backdrop="true">
|
<b-sidebar id="sidebar-mobile" :backdrop="true" bg-variant="transparent">
|
||||||
<div class="px-3 py-2">
|
<div class="px-3 py-2">
|
||||||
<sidebar @admin="$emit('admin')" @logout="$emit('logout')" />
|
<sidebar @admin="$emit('admin')" @logout="$emit('logout')" :shadow="false" />
|
||||||
</div>
|
</div>
|
||||||
<template #header>
|
|
||||||
<div>
|
|
||||||
<div class="mr-auto">{{ avatarLongName }}</div>
|
|
||||||
<div class="small">
|
|
||||||
<small>{{ $store.state.email }}</small>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<template #footer>
|
|
||||||
<div class="d-flex bg-light">
|
|
||||||
<strong class="mr-auto p-2">{{ $t('send_gdd') }}</strong>
|
|
||||||
<b-button to="/send"><b-icon icon="arrow-right"></b-icon></b-button>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</b-sidebar>
|
</b-sidebar>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@ -29,10 +15,5 @@ export default {
|
|||||||
components: {
|
components: {
|
||||||
Sidebar,
|
Sidebar,
|
||||||
},
|
},
|
||||||
computed: {
|
|
||||||
avatarLongName() {
|
|
||||||
return `${this.$store.state.firstName} ${this.$store.state.lastName}`
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -7,23 +7,25 @@
|
|||||||
>
|
>
|
||||||
<b-card-body>
|
<b-card-body>
|
||||||
<b-card-title class="h2">{{ item.text }}</b-card-title>
|
<b-card-title class="h2">{{ item.text }}</b-card-title>
|
||||||
</b-card-body>
|
|
||||||
<b-card-footer class="bg-transparent">
|
<div class="h3">{{ item.date }}</div>
|
||||||
|
|
||||||
<b-row class="my-5">
|
<b-row class="my-5">
|
||||||
<b-col cols="12" md="6" lg="6">
|
<b-col>
|
||||||
<div class="h3">{{ item.date }}</div>
|
{{ item.extra }}
|
||||||
</b-col>
|
</b-col>
|
||||||
<b-col cols="12" md="6" lg="6">
|
</b-row>
|
||||||
<div class="text-right">
|
|
||||||
|
<b-row class="my-5">
|
||||||
|
<b-col cols="12">
|
||||||
|
<div class="text-lg-right">
|
||||||
<b-button variant="gradido" :href="item.url" target="_blank">
|
<b-button variant="gradido" :href="item.url" target="_blank">
|
||||||
{{ $t('auth.left.learnMore') }}
|
{{ $t('auth.left.learnMore') }}
|
||||||
</b-button>
|
</b-button>
|
||||||
</div>
|
</div>
|
||||||
</b-col>
|
</b-col>
|
||||||
</b-row>
|
</b-row>
|
||||||
|
</b-card-body>
|
||||||
{{ item.extra }}
|
|
||||||
</b-card-footer>
|
|
||||||
</b-card>
|
</b-card>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -22,6 +22,10 @@
|
|||||||
<b-icon icon="x-circle" variant="danger"></b-icon>
|
<b-icon icon="x-circle" variant="danger"></b-icon>
|
||||||
{{ $t('contribution.alert.rejected') }}
|
{{ $t('contribution.alert.rejected') }}
|
||||||
</li>
|
</li>
|
||||||
|
<li>
|
||||||
|
<b-icon icon="trash" variant="danger"></b-icon>
|
||||||
|
{{ $t('contribution.alert.deleted') }}
|
||||||
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="hash === '#all'" show fade variant="secondary" class="text-dark">
|
<div v-if="hash === '#all'" show fade variant="secondary" class="text-dark">
|
||||||
|
|||||||
@ -17,6 +17,12 @@ const mocks = {
|
|||||||
$apollo: {
|
$apollo: {
|
||||||
query: apolloQueryMock,
|
query: apolloQueryMock,
|
||||||
},
|
},
|
||||||
|
$store: {
|
||||||
|
state: {
|
||||||
|
firstName: 'Bibi',
|
||||||
|
lastName: 'Bloxberg',
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
const propsData = {
|
const propsData = {
|
||||||
@ -102,10 +108,10 @@ describe('TransactionLinkSummary', () => {
|
|||||||
|
|
||||||
describe('click on transaction links', () => {
|
describe('click on transaction links', () => {
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
wrapper.find('div.transaction-slot-link').trigger('click')
|
wrapper.find('div.row').trigger('click')
|
||||||
})
|
})
|
||||||
|
|
||||||
it.skip('calls the API to get the list transaction links', () => {
|
it('calls the API to get the list transaction links', () => {
|
||||||
expect(apolloQueryMock).toBeCalledWith({
|
expect(apolloQueryMock).toBeCalledWith({
|
||||||
query: listTransactionLinks,
|
query: listTransactionLinks,
|
||||||
variables: {
|
variables: {
|
||||||
@ -115,14 +121,14 @@ describe('TransactionLinkSummary', () => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
it.skip('has four transactionLinks', () => {
|
it('has four transactionLinks', () => {
|
||||||
expect(wrapper.vm.transactionLinks).toHaveLength(4)
|
expect(wrapper.vm.transactionLinks).toHaveLength(4)
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('close transaction link details', () => {
|
describe('close transaction link details', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
jest.clearAllMocks()
|
jest.clearAllMocks()
|
||||||
wrapper.find('div.transaction-slot-link').trigger('click')
|
wrapper.find('div.row').trigger('click')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('does not call the API', () => {
|
it('does not call the API', () => {
|
||||||
@ -136,10 +142,10 @@ describe('TransactionLinkSummary', () => {
|
|||||||
describe('reopen transaction link details', () => {
|
describe('reopen transaction link details', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
jest.clearAllMocks()
|
jest.clearAllMocks()
|
||||||
wrapper.find('div.transaction-slot-link').trigger('click')
|
wrapper.find('div.row').trigger('click')
|
||||||
})
|
})
|
||||||
|
|
||||||
it.skip('calls the API to get the list transaction links', () => {
|
it('calls the API to get the list transaction links', () => {
|
||||||
expect(apolloQueryMock).toBeCalledWith({
|
expect(apolloQueryMock).toBeCalledWith({
|
||||||
query: listTransactionLinks,
|
query: listTransactionLinks,
|
||||||
variables: {
|
variables: {
|
||||||
@ -149,7 +155,7 @@ describe('TransactionLinkSummary', () => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
it.skip('has four transactionLinks', () => {
|
it('has four transactionLinks', () => {
|
||||||
expect(wrapper.vm.transactionLinks).toHaveLength(4)
|
expect(wrapper.vm.transactionLinks).toHaveLength(4)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@ -215,7 +221,7 @@ describe('TransactionLinkSummary', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('has eight transactionLinks', () => {
|
it('has eight transactionLinks', () => {
|
||||||
expect(wrapper.vm.transactionLinks).toHaveLength(4)
|
expect(wrapper.vm.transactionLinks).toHaveLength(8)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('loads more transaction links', () => {
|
it('loads more transaction links', () => {
|
||||||
@ -230,19 +236,19 @@ describe('TransactionLinkSummary', () => {
|
|||||||
|
|
||||||
describe('close transaction link list', () => {
|
describe('close transaction link list', () => {
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
wrapper.find('div.transaction-slot-link').trigger('click')
|
wrapper.find('div.row').trigger('click')
|
||||||
})
|
})
|
||||||
describe('reopen transaction link list', () => {
|
describe('reopen transaction link list', () => {
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
jest.clearAllMocks()
|
jest.clearAllMocks()
|
||||||
wrapper.find('div.transaction-slot-link').trigger('click')
|
wrapper.find('div.row').trigger('click')
|
||||||
})
|
})
|
||||||
|
|
||||||
it.skip('calls the API once', () => {
|
it('calls the API once', () => {
|
||||||
expect(apolloQueryMock).toBeCalledTimes(1)
|
expect(apolloQueryMock).toBeCalledTimes(1)
|
||||||
})
|
})
|
||||||
|
|
||||||
it.skip('calls the API with current page one', () => {
|
it('calls the API with current page one', () => {
|
||||||
expect(apolloQueryMock).toBeCalledWith({
|
expect(apolloQueryMock).toBeCalledWith({
|
||||||
query: listTransactionLinks,
|
query: listTransactionLinks,
|
||||||
variables: {
|
variables: {
|
||||||
@ -289,10 +295,10 @@ describe('TransactionLinkSummary', () => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe.skip('loads transaction links with error', () => {
|
describe('loads transaction links with error', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
apolloQueryMock.mockRejectedValue({ message: 'OUCH!' })
|
apolloQueryMock.mockRejectedValue({ message: 'OUCH!' })
|
||||||
wrapper.find('div.transaction-slot-link').trigger('click')
|
wrapper.find('div.row').trigger('click')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('toasts an error message', () => {
|
it('toasts an error message', () => {
|
||||||
|
|||||||
@ -1,41 +1,46 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="userdata-card">
|
<div class="userdata-card">
|
||||||
<b-row>
|
<div class="centerPerMargin">
|
||||||
<b-col class="centerPerMargin">
|
<avatar
|
||||||
<avatar
|
:username="username.username"
|
||||||
:username="username.username"
|
:initials="username.initials"
|
||||||
:initials="username.initials"
|
:color="'#fff'"
|
||||||
:color="'#fff'"
|
:size="90"
|
||||||
:size="90"
|
></avatar>
|
||||||
></avatar>
|
</div>
|
||||||
</b-col>
|
|
||||||
</b-row>
|
<div class="justify-content-center mt-5 mb-5">
|
||||||
<b-card class="border-0">
|
<b-row align-v="stretch">
|
||||||
<b-container class="justify-content-center mt-md-5">
|
<b-col cols="4">
|
||||||
<b-row>
|
<div class="text-center font-weight-bold">
|
||||||
<b-col>
|
{{ $n(balance, 'decimal') }}
|
||||||
<div class="text-center font-weight-bold">
|
</div>
|
||||||
{{ $n(balance, 'decimal') }}
|
</b-col>
|
||||||
</div>
|
<b-col cols="4">
|
||||||
<div class="text-center">{{ $t('GDD') }}</div>
|
<div class="text-center font-weight-bold">
|
||||||
</b-col>
|
{{ transactionCount }}
|
||||||
<b-col>
|
</div>
|
||||||
<div class="text-center font-weight-bold">
|
</b-col>
|
||||||
{{ transactionCount }}
|
<b-col cols="4">
|
||||||
</div>
|
<div class="text-center font-weight-bold">{{ CONFIG.COMMUNITY_NAME }}</div>
|
||||||
<div class="text-center">
|
</b-col>
|
||||||
{{ $t('navigation.transactions') }}
|
</b-row>
|
||||||
</div>
|
<b-row>
|
||||||
</b-col>
|
<b-col cols="4">
|
||||||
<b-col>
|
<div class="text-center">{{ $t('GDD') }}</div>
|
||||||
<div class="text-center font-weight-bold">{{ CONFIG.COMMUNITY_NAME }}</div>
|
</b-col>
|
||||||
<div class="text-center">
|
<b-col cols="4">
|
||||||
{{ $t('community.community') }}
|
<div class="text-center">
|
||||||
</div>
|
{{ $t('navigation.transactions') }}
|
||||||
</b-col>
|
</div>
|
||||||
</b-row>
|
</b-col>
|
||||||
</b-container>
|
<b-col cols="4">
|
||||||
</b-card>
|
<div class="text-center">
|
||||||
|
{{ $t('community.community') }}
|
||||||
|
</div>
|
||||||
|
</b-col>
|
||||||
|
</b-row>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
@ -70,4 +75,14 @@ export default {
|
|||||||
.centerPerMargin {
|
.centerPerMargin {
|
||||||
padding-left: 44%;
|
padding-left: 44%;
|
||||||
}
|
}
|
||||||
|
@media screen and (max-width: 850px) {
|
||||||
|
.centerPerMargin {
|
||||||
|
padding-left: 38%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@media screen and (max-width: 450px) {
|
||||||
|
.centerPerMargin {
|
||||||
|
padding-left: 34%;
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@ -13,7 +13,6 @@ export const verifyLogin = gql`
|
|||||||
hasElopage
|
hasElopage
|
||||||
publisherId
|
publisherId
|
||||||
isAdmin
|
isAdmin
|
||||||
creation
|
|
||||||
hideAmountGDD
|
hideAmountGDD
|
||||||
hideAmountGDT
|
hideAmountGDT
|
||||||
}
|
}
|
||||||
|
|||||||
@ -15,6 +15,7 @@ const routerPushMock = jest.fn()
|
|||||||
const stubs = {
|
const stubs = {
|
||||||
RouterLink: RouterLinkStub,
|
RouterLink: RouterLinkStub,
|
||||||
RouterView: true,
|
RouterView: true,
|
||||||
|
LastTransactions: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
const mocks = {
|
const mocks = {
|
||||||
@ -29,6 +30,9 @@ const mocks = {
|
|||||||
meta: {
|
meta: {
|
||||||
hideFooter: false,
|
hideFooter: false,
|
||||||
},
|
},
|
||||||
|
path: {
|
||||||
|
replace: jest.fn(),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
$router: {
|
$router: {
|
||||||
push: routerPushMock,
|
push: routerPushMock,
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
<div v-if="skeleton">
|
<div v-if="skeleton">
|
||||||
<skeleton-overview />
|
<skeleton-overview />
|
||||||
</div>
|
</div>
|
||||||
<div v-else>
|
<div v-else class="mx-lg-0">
|
||||||
<!-- navbar -->
|
<!-- navbar -->
|
||||||
<b-row>
|
<b-row>
|
||||||
<b-col>
|
<b-col>
|
||||||
@ -13,7 +13,7 @@
|
|||||||
<mobile-sidebar @admin="admin" @logout="logout" />
|
<mobile-sidebar @admin="admin" @logout="logout" />
|
||||||
|
|
||||||
<!-- Breadcrumb -->
|
<!-- Breadcrumb -->
|
||||||
<b-row>
|
<b-row class="breadcrumb">
|
||||||
<b-col cols="10" offset-lg="2">
|
<b-col cols="10" offset-lg="2">
|
||||||
<breadcrumb />
|
<breadcrumb />
|
||||||
</b-col>
|
</b-col>
|
||||||
@ -35,7 +35,87 @@
|
|||||||
:balance="balance"
|
:balance="balance"
|
||||||
:GdtBalance="GdtBalance"
|
:GdtBalance="GdtBalance"
|
||||||
:totalUsers="totalUsers"
|
:totalUsers="totalUsers"
|
||||||
/>
|
>
|
||||||
|
<template #overview>
|
||||||
|
<b-row>
|
||||||
|
<b-col cols="12" lg="5">
|
||||||
|
<div>
|
||||||
|
<gdd-amount :balance="balance" :showStatus="false" :badgeShow="false" />
|
||||||
|
</div>
|
||||||
|
</b-col>
|
||||||
|
<b-col cols="12" lg="7">
|
||||||
|
<div>
|
||||||
|
<community-member :totalUsers="totalUsers" />
|
||||||
|
</div>
|
||||||
|
</b-col>
|
||||||
|
</b-row>
|
||||||
|
</template>
|
||||||
|
<template #send>
|
||||||
|
<b-row>
|
||||||
|
<b-col cols="12" lg="6">
|
||||||
|
<div>
|
||||||
|
<gdd-amount
|
||||||
|
:balance="balance"
|
||||||
|
:badge="true"
|
||||||
|
:showStatus="true"
|
||||||
|
:badgeShow="false"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</b-col>
|
||||||
|
<b-col cols="12" lg="6">
|
||||||
|
<div>
|
||||||
|
<router-link to="gdt">
|
||||||
|
<gdt-amount :GdtBalance="GdtBalance" :badgeShow="false" />
|
||||||
|
</router-link>
|
||||||
|
</div>
|
||||||
|
</b-col>
|
||||||
|
</b-row>
|
||||||
|
</template>
|
||||||
|
<template #transactions>
|
||||||
|
<b-row>
|
||||||
|
<b-col cols="12" lg="6">
|
||||||
|
<div>
|
||||||
|
<router-link to="transactions">
|
||||||
|
<gdd-amount :balance="balance" :showStatus="true" />
|
||||||
|
</router-link>
|
||||||
|
</div>
|
||||||
|
</b-col>
|
||||||
|
<b-col cols="12" lg="6">
|
||||||
|
<div>
|
||||||
|
<router-link to="gdt">
|
||||||
|
<gdt-amount :GdtBalance="GdtBalance" />
|
||||||
|
</router-link>
|
||||||
|
</div>
|
||||||
|
</b-col>
|
||||||
|
</b-row>
|
||||||
|
</template>
|
||||||
|
<template #gdt>
|
||||||
|
<b-row>
|
||||||
|
<b-col cols="12" lg="6">
|
||||||
|
<div>
|
||||||
|
<router-link to="transactions">
|
||||||
|
<gdd-amount :balance="balance" :showStatus="false" />
|
||||||
|
</router-link>
|
||||||
|
</div>
|
||||||
|
</b-col>
|
||||||
|
<b-col cols="12" lg="6">
|
||||||
|
<div>
|
||||||
|
<router-link to="gdt">
|
||||||
|
<gdt-amount
|
||||||
|
:badge="true"
|
||||||
|
:showStatus="true"
|
||||||
|
:GdtBalance="GdtBalance"
|
||||||
|
/>
|
||||||
|
</router-link>
|
||||||
|
</div>
|
||||||
|
</b-col>
|
||||||
|
</b-row>
|
||||||
|
</template>
|
||||||
|
<template #community>
|
||||||
|
<nav-community />
|
||||||
|
</template>
|
||||||
|
<template #settings></template>
|
||||||
|
</content-header>
|
||||||
</b-col>
|
</b-col>
|
||||||
</b-row>
|
</b-row>
|
||||||
</b-col>
|
</b-col>
|
||||||
@ -45,12 +125,24 @@
|
|||||||
:transactions="transactions"
|
:transactions="transactions"
|
||||||
:transactionCount="transactionCount"
|
:transactionCount="transactionCount"
|
||||||
:transactionLinkCount="transactionLinkCount"
|
:transactionLinkCount="transactionLinkCount"
|
||||||
@set-tunneled-email="setTunneledEmail"
|
>
|
||||||
/>
|
<template #transactions>
|
||||||
|
<last-transactions
|
||||||
|
:transactions="transactions"
|
||||||
|
:transactionCount="transactionCount"
|
||||||
|
:transactionLinkCount="transactionLinkCount"
|
||||||
|
@set-tunneled-email="setTunneledEmail"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
<template #community>
|
||||||
|
<contribution-info />
|
||||||
|
</template>
|
||||||
|
<template #empty />
|
||||||
|
</right-side>
|
||||||
</b-col>
|
</b-col>
|
||||||
<b-col cols="12">
|
<b-col cols="12">
|
||||||
<!-- router-view -->
|
<!-- router-view -->
|
||||||
<div class="main-content mt-3">
|
<div class="main-content mt-lg-3 mt-0">
|
||||||
<fade-transition :duration="200" origin="center top" mode="out-in">
|
<fade-transition :duration="200" origin="center top" mode="out-in">
|
||||||
<router-view
|
<router-view
|
||||||
ref="router-view"
|
ref="router-view"
|
||||||
@ -74,8 +166,20 @@
|
|||||||
:transactions="transactions"
|
:transactions="transactions"
|
||||||
:transactionCount="transactionCount"
|
:transactionCount="transactionCount"
|
||||||
:transactionLinkCount="transactionLinkCount"
|
:transactionLinkCount="transactionLinkCount"
|
||||||
@set-tunneled-email="setTunneledEmail"
|
>
|
||||||
/>
|
<template #transactions>
|
||||||
|
<last-transactions
|
||||||
|
:transactions="transactions"
|
||||||
|
:transactionCount="transactionCount"
|
||||||
|
:transactionLinkCount="transactionLinkCount"
|
||||||
|
@set-tunneled-email="setTunneledEmail"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
<template #community>
|
||||||
|
<contribution-info />
|
||||||
|
</template>
|
||||||
|
<template #empty />
|
||||||
|
</right-side>
|
||||||
</b-col>
|
</b-col>
|
||||||
</b-row>
|
</b-row>
|
||||||
<b-row>
|
<b-row>
|
||||||
@ -102,6 +206,12 @@ import { logout } from '@/graphql/mutations'
|
|||||||
import ContentFooter from '@/components/ContentFooter.vue'
|
import ContentFooter from '@/components/ContentFooter.vue'
|
||||||
import { FadeTransition } from 'vue2-transitions'
|
import { FadeTransition } from 'vue2-transitions'
|
||||||
import CONFIG from '@/config'
|
import CONFIG from '@/config'
|
||||||
|
import GddAmount from '@/components/Template/ContentHeader/GddAmount.vue'
|
||||||
|
import GdtAmount from '@/components/Template/ContentHeader/GdtAmount.vue'
|
||||||
|
import CommunityMember from '@/components/Template/ContentHeader/CommunityMember.vue'
|
||||||
|
import NavCommunity from '@/components/Template/ContentHeader/NavCommunity.vue'
|
||||||
|
import LastTransactions from '@/components/Template/RightSide/LastTransactions.vue'
|
||||||
|
import ContributionInfo from '@/components/Template/RightSide/ContributionInfo.vue'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'DashboardLayout',
|
name: 'DashboardLayout',
|
||||||
@ -116,6 +226,12 @@ export default {
|
|||||||
ContentFooter,
|
ContentFooter,
|
||||||
FadeTransition,
|
FadeTransition,
|
||||||
Breadcrumb,
|
Breadcrumb,
|
||||||
|
GddAmount,
|
||||||
|
GdtAmount,
|
||||||
|
CommunityMember,
|
||||||
|
NavCommunity,
|
||||||
|
LastTransactions,
|
||||||
|
ContributionInfo,
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
@ -218,7 +334,9 @@ export default {
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<style>
|
<style>
|
||||||
/* frontend/public/img/svg/Gradido_Blaetter_Mainpage.svg */
|
.breadcrumb {
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
.main-page {
|
.main-page {
|
||||||
background-attachment: fixed;
|
background-attachment: fixed;
|
||||||
background-position: center;
|
background-position: center;
|
||||||
@ -251,4 +369,10 @@ export default {
|
|||||||
.navbar-toggler-icon {
|
.navbar-toggler-icon {
|
||||||
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='30' height='30' viewBox='0 0 30 30'%3e%3cpath stroke='rgba(4, 112, 6, 1)' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e");
|
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='30' height='30' viewBox='0 0 30 30'%3e%3cpath stroke='rgba(4, 112, 6, 1)' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@media screen and (max-width: 450px) {
|
||||||
|
.breadcrumb {
|
||||||
|
padding-top: 60px;
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@ -1,116 +1,15 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<div v-if="path === '/overview'">
|
<slot :name="path" />
|
||||||
<b-row>
|
|
||||||
<b-col cols="12" lg="5">
|
|
||||||
<div>
|
|
||||||
<gdd-amount :balance="balance" :showStatus="false" :path="path" :badgeShow="false" />
|
|
||||||
</div>
|
|
||||||
</b-col>
|
|
||||||
<b-col cols="12" lg="7">
|
|
||||||
<div>
|
|
||||||
<community-member :totalUsers="totalUsers" />
|
|
||||||
</div>
|
|
||||||
</b-col>
|
|
||||||
</b-row>
|
|
||||||
</div>
|
|
||||||
<!-- <div v-if="path === '/storys'"></div>
|
|
||||||
<div v-if="path === '/addresses'"></div> -->
|
|
||||||
<div v-if="path === '/send'">
|
|
||||||
<b-row>
|
|
||||||
<b-col cols="12" lg="6">
|
|
||||||
<div>
|
|
||||||
<gdd-amount :balance="balance" :badge="true" :showStatus="true" :badgeShow="false" />
|
|
||||||
</div>
|
|
||||||
</b-col>
|
|
||||||
<b-col cols="12" lg="6">
|
|
||||||
<div>
|
|
||||||
<router-link to="gdt">
|
|
||||||
<gdt-amount :GdtBalance="GdtBalance" :badgeShow="false" />
|
|
||||||
</router-link>
|
|
||||||
</div>
|
|
||||||
</b-col>
|
|
||||||
</b-row>
|
|
||||||
</div>
|
|
||||||
<div v-if="path === '/transactions'">
|
|
||||||
<b-row>
|
|
||||||
<b-col cols="12" lg="6">
|
|
||||||
<div>
|
|
||||||
<router-link to="transactions">
|
|
||||||
<gdd-amount :balance="balance" :showStatus="true" />
|
|
||||||
</router-link>
|
|
||||||
</div>
|
|
||||||
</b-col>
|
|
||||||
<b-col cols="12" lg="6">
|
|
||||||
<div>
|
|
||||||
<router-link to="gdt">
|
|
||||||
<gdt-amount :GdtBalance="GdtBalance" />
|
|
||||||
</router-link>
|
|
||||||
</div>
|
|
||||||
</b-col>
|
|
||||||
</b-row>
|
|
||||||
</div>
|
|
||||||
<div v-if="path === '/gdt'">
|
|
||||||
<b-row>
|
|
||||||
<b-col cols="12" lg="6">
|
|
||||||
<div>
|
|
||||||
<router-link to="transactions">
|
|
||||||
<gdd-amount :balance="balance" :showStatus="false" />
|
|
||||||
</router-link>
|
|
||||||
</div>
|
|
||||||
</b-col>
|
|
||||||
<b-col cols="12" lg="6">
|
|
||||||
<div>
|
|
||||||
<router-link to="gdt">
|
|
||||||
<gdt-amount :badge="true" :showStatus="true" :GdtBalance="GdtBalance" />
|
|
||||||
</router-link>
|
|
||||||
</div>
|
|
||||||
</b-col>
|
|
||||||
</b-row>
|
|
||||||
</div>
|
|
||||||
<!-- <div v-if="path === '/profile'">
|
|
||||||
<b-row>
|
|
||||||
<b-col>
|
|
||||||
<div class="p-4 bg-white appBoxShadow gradido-border-radius">
|
|
||||||
<b-row>
|
|
||||||
<b-col cols="8" class="h3">Zeige deiner Community wer du bist.</b-col>
|
|
||||||
<b-col cols="4" class="text-small text-muted">vor 4 Stunden geändert</b-col>
|
|
||||||
</b-row>
|
|
||||||
<b-row>
|
|
||||||
<b-col cols="2" class=""><b-avatar size="72px" rounded="lg"></b-avatar></b-col>
|
|
||||||
<b-col cols="10" class="">Text</b-col>
|
|
||||||
</b-row>
|
|
||||||
</div>
|
|
||||||
</b-col>
|
|
||||||
</b-row>
|
|
||||||
</div> -->
|
|
||||||
<div v-if="path === '/community'"><nav-community /></div>
|
|
||||||
<div v-if="path === '/settings'"></div>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import GddAmount from '@/components/Template/ContentHeader/GddAmount.vue'
|
|
||||||
import GdtAmount from '@/components/Template/ContentHeader/GdtAmount.vue'
|
|
||||||
import CommunityMember from '@/components/Template/ContentHeader/CommunityMember.vue'
|
|
||||||
import NavCommunity from '@/components/Template/ContentHeader/NavCommunity.vue'
|
|
||||||
export default {
|
export default {
|
||||||
name: 'ContentHeader',
|
name: 'ContentHeader',
|
||||||
components: {
|
|
||||||
GddAmount,
|
|
||||||
GdtAmount,
|
|
||||||
CommunityMember,
|
|
||||||
NavCommunity,
|
|
||||||
},
|
|
||||||
props: {
|
|
||||||
balance: { type: Number, required: true },
|
|
||||||
GdtBalance: { type: Number, required: true },
|
|
||||||
totalUsers: { type: Number, required: true },
|
|
||||||
},
|
|
||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
path() {
|
path() {
|
||||||
return this.$route.path
|
return this.$route.path.replace(/^\//, '')
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,157 +1,23 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="right-side mt-3 mt-lg-0">
|
<div class="right-side mt-3 mt-lg-0">
|
||||||
<b-container v-if="path === '/overview'" fluid="md">
|
<b-container>
|
||||||
<!-- <b-row>
|
<slot :name="name" />
|
||||||
<b-col>
|
|
||||||
<div class="p-4">
|
|
||||||
<favourites />
|
|
||||||
</div>
|
|
||||||
</b-col>
|
|
||||||
</b-row> -->
|
|
||||||
<b-row>
|
|
||||||
<b-col>
|
|
||||||
<div>
|
|
||||||
<last-transactions
|
|
||||||
:transactions="transactions"
|
|
||||||
:transactionCount="transactionCount"
|
|
||||||
:transactionLinkCount="transactionLinkCount"
|
|
||||||
v-on="$listeners"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</b-col>
|
|
||||||
</b-row>
|
|
||||||
</b-container>
|
</b-container>
|
||||||
<!-- <b-container v-if="path === '/storys'">
|
|
||||||
<b-row>
|
|
||||||
<b-col>
|
|
||||||
<div class="p-4">
|
|
||||||
<favourites />
|
|
||||||
</div>
|
|
||||||
</b-col>
|
|
||||||
</b-row>
|
|
||||||
<b-row class="mt-3 mt-lg-5">
|
|
||||||
<b-col>
|
|
||||||
<div class="p-4 h-100">
|
|
||||||
<top-storys-by-month />
|
|
||||||
</div>
|
|
||||||
</b-col>
|
|
||||||
</b-row>
|
|
||||||
</b-container> -->
|
|
||||||
<!-- <b-container v-if="path === '/addresses'">favourites ride side</b-container> -->
|
|
||||||
<b-container v-if="path === '/send'">
|
|
||||||
<!-- <b-row>
|
|
||||||
<b-col>
|
|
||||||
<div class="p-4">
|
|
||||||
<favourites />
|
|
||||||
</div>
|
|
||||||
</b-col>
|
|
||||||
</b-row> -->
|
|
||||||
<b-row>
|
|
||||||
<b-col>
|
|
||||||
<div>
|
|
||||||
<last-transactions
|
|
||||||
:transactions="transactions"
|
|
||||||
:transactionCount="transactionCount"
|
|
||||||
:transactionLinkCount="transactionLinkCount"
|
|
||||||
v-on="$listeners"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</b-col>
|
|
||||||
</b-row>
|
|
||||||
</b-container>
|
|
||||||
<b-container v-if="path === '/transactions'">
|
|
||||||
<!-- <b-row>
|
|
||||||
<b-col>
|
|
||||||
<div class="p-4">
|
|
||||||
<favourites />
|
|
||||||
</div>
|
|
||||||
</b-col>
|
|
||||||
</b-row> -->
|
|
||||||
<b-row>
|
|
||||||
<b-col>
|
|
||||||
<div>
|
|
||||||
<last-transactions
|
|
||||||
:transactions="transactions"
|
|
||||||
:transactionCount="transactionCount"
|
|
||||||
:transactionLinkCount="transactionLinkCount"
|
|
||||||
v-on="$listeners"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</b-col>
|
|
||||||
</b-row>
|
|
||||||
</b-container>
|
|
||||||
<b-container v-if="path === '/gdt'">
|
|
||||||
<!-- <b-row>
|
|
||||||
<b-col>
|
|
||||||
<div class="p-4">
|
|
||||||
<favourites />
|
|
||||||
</div>
|
|
||||||
</b-col>
|
|
||||||
</b-row> -->
|
|
||||||
<b-row>
|
|
||||||
<b-col>
|
|
||||||
<div>
|
|
||||||
<last-transactions
|
|
||||||
:transactions="transactions"
|
|
||||||
:transactionCount="transactionCount"
|
|
||||||
:transactionLinkCount="transactionLinkCount"
|
|
||||||
v-on="$listeners"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</b-col>
|
|
||||||
</b-row>
|
|
||||||
</b-container>
|
|
||||||
<!-- <b-container v-if="path === '/profile'">
|
|
||||||
<b-row>
|
|
||||||
<b-col>
|
|
||||||
<div class="p-4">
|
|
||||||
<favourites />
|
|
||||||
</div>
|
|
||||||
</b-col>
|
|
||||||
</b-row>
|
|
||||||
<b-row class="mt-3 mt-lg-5">
|
|
||||||
<b-col>
|
|
||||||
<div class="p-4 h-100">
|
|
||||||
<your-overview />
|
|
||||||
</div>
|
|
||||||
</b-col>
|
|
||||||
</b-row>
|
|
||||||
</b-container> -->
|
|
||||||
<b-container v-if="path === '/community'">
|
|
||||||
<contribution-info />
|
|
||||||
<!-- <last-contributions class="mt-5" /> -->
|
|
||||||
</b-container>
|
|
||||||
<b-container v-if="path === '/settings'"></b-container>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
import LastTransactions from '@/components/Template/RightSide/LastTransactions.vue'
|
|
||||||
// import Favourites from '@/components/Template/RightSide/Favourites.vue'
|
|
||||||
// import TopStorysByMonth from '@/components/Template/RightSide/TopStorysByMonth.vue'
|
|
||||||
import ContributionInfo from '@/components/Template/RightSide/ContributionInfo.vue'
|
|
||||||
// import LastContributions from '@/components/Template/RightSide/LastContributions.vue'
|
|
||||||
// import YourOverview from '@/components/Template/RightSide/YourOverview.vue'
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'RightSide',
|
name: 'RightSide',
|
||||||
components: {
|
|
||||||
LastTransactions,
|
|
||||||
// Favourites,
|
|
||||||
// TopStorysByMonth,
|
|
||||||
// LastContributions,
|
|
||||||
ContributionInfo,
|
|
||||||
// YourOverview,
|
|
||||||
},
|
|
||||||
props: {
|
|
||||||
transactions: {
|
|
||||||
default: () => [],
|
|
||||||
},
|
|
||||||
transactionCount: { type: Number, default: 0 },
|
|
||||||
transactionLinkCount: { type: Number, default: 0 },
|
|
||||||
},
|
|
||||||
computed: {
|
computed: {
|
||||||
path() {
|
name() {
|
||||||
return this.$route.path
|
switch (this.$route.path.replace(/^\//, '')) {
|
||||||
|
case 'settings':
|
||||||
|
return 'empty'
|
||||||
|
case 'community':
|
||||||
|
return 'community'
|
||||||
|
default:
|
||||||
|
return 'transactions'
|
||||||
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@ -30,16 +30,18 @@
|
|||||||
"noOpenContributionLinkText": "Zur Zeit gibt es keine automatischen Schöpfungen.",
|
"noOpenContributionLinkText": "Zur Zeit gibt es keine automatischen Schöpfungen.",
|
||||||
"openContributionLinks": "Öffentliche Beitrags-Linkliste",
|
"openContributionLinks": "Öffentliche Beitrags-Linkliste",
|
||||||
"openContributionLinkText": "Folgende {count} automatische Schöpfungen werden zur Zeit durch die Gemeinschaft „{name}“ bereitgestellt.",
|
"openContributionLinkText": "Folgende {count} automatische Schöpfungen werden zur Zeit durch die Gemeinschaft „{name}“ bereitgestellt.",
|
||||||
"submitContribution": "schreiben"
|
"submitContribution": "Schreiben"
|
||||||
},
|
},
|
||||||
"communityInfo": "Gemeinschaft Information",
|
"communityInfo": "Gemeinschaft Information",
|
||||||
"contact": "Kontakt",
|
"contact": "Kontakt",
|
||||||
"contribution": {
|
"contribution": {
|
||||||
"activity": "Tätigkeit",
|
"activity": "Tätigkeit",
|
||||||
"alert": {
|
"alert": {
|
||||||
"answerQuestion": "Bitte beantworte die Rückfrage!",
|
"answerQuestion": "Bitte beantworte diese Rückfrage.",
|
||||||
|
"answerQuestionToast": "Du hast eine Rückfrage auf einen Beitrag. Bitte antworte auf diese.",
|
||||||
"communityNoteList": "Hier findest du alle eingereichten und bestätigten Beiträge von allen Mitgliedern aus dieser Gemeinschaft.",
|
"communityNoteList": "Hier findest du alle eingereichten und bestätigten Beiträge von allen Mitgliedern aus dieser Gemeinschaft.",
|
||||||
"confirm": "bestätigt",
|
"confirm": "bestätigt",
|
||||||
|
"deleted": "gelöscht",
|
||||||
"in_progress": "Es gibt eine Rückfrage der Moderatoren.",
|
"in_progress": "Es gibt eine Rückfrage der Moderatoren.",
|
||||||
"myContributionNoteList": "Eingereichte Beiträge, die noch nicht bestätigt wurden, kannst du jederzeit bearbeiten oder löschen.",
|
"myContributionNoteList": "Eingereichte Beiträge, die noch nicht bestätigt wurden, kannst du jederzeit bearbeiten oder löschen.",
|
||||||
"pending": "Eingereicht und wartet auf Bestätigung",
|
"pending": "Eingereicht und wartet auf Bestätigung",
|
||||||
@ -47,7 +49,6 @@
|
|||||||
},
|
},
|
||||||
"delete": "Beitrag löschen! Bist du sicher?",
|
"delete": "Beitrag löschen! Bist du sicher?",
|
||||||
"deleted": "Der Beitrag wurde gelöscht! Wird aber sichtbar bleiben.",
|
"deleted": "Der Beitrag wurde gelöscht! Wird aber sichtbar bleiben.",
|
||||||
"exhausted": "Für diesen Monat kannst du nichts mehr schöpfen.",
|
|
||||||
"formText": {
|
"formText": {
|
||||||
"bringYourTalentsTo": "Bring dich mit deinen Talenten in die Gemeinschaft ein! Dein freiwilliges Engagement honorieren wir mit 20 GDD pro Stunde bis maximal 1.000 GDD im Monat.",
|
"bringYourTalentsTo": "Bring dich mit deinen Talenten in die Gemeinschaft ein! Dein freiwilliges Engagement honorieren wir mit 20 GDD pro Stunde bis maximal 1.000 GDD im Monat.",
|
||||||
"describeYourCommunity": "Beschreibe deine Gemeinwohl-Tätigkeit mit Angabe der Stunden und trage einen Betrag von 20 GDD pro Stunde ein! Nach Bestätigung durch einen Moderator wird der Betrag deinem Konto gutgeschrieben.",
|
"describeYourCommunity": "Beschreibe deine Gemeinwohl-Tätigkeit mit Angabe der Stunden und trage einen Betrag von 20 GDD pro Stunde ein! Nach Bestätigung durch einen Moderator wird der Betrag deinem Konto gutgeschrieben.",
|
||||||
@ -215,7 +216,6 @@
|
|||||||
},
|
},
|
||||||
"h": "h",
|
"h": "h",
|
||||||
"language": "Sprache",
|
"language": "Sprache",
|
||||||
"lastMonth": "letzter Monat",
|
|
||||||
"link-load": "den letzten Link nachladen | die letzten {n} Links nachladen | weitere {n} Links nachladen",
|
"link-load": "den letzten Link nachladen | die letzten {n} Links nachladen | weitere {n} Links nachladen",
|
||||||
"login": "Anmelden",
|
"login": "Anmelden",
|
||||||
"math": {
|
"math": {
|
||||||
|
|||||||
@ -30,16 +30,18 @@
|
|||||||
"noOpenContributionLinkText": "Currently there are no automatic creations.",
|
"noOpenContributionLinkText": "Currently there are no automatic creations.",
|
||||||
"openContributionLinks": "Open contribution-link list",
|
"openContributionLinks": "Open contribution-link list",
|
||||||
"openContributionLinkText": "The following {count} automatic creations are currently provided by the \"{name}\" community.",
|
"openContributionLinkText": "The following {count} automatic creations are currently provided by the \"{name}\" community.",
|
||||||
"submitContribution": "writing"
|
"submitContribution": "Contribute"
|
||||||
},
|
},
|
||||||
"communityInfo": "Community Information",
|
"communityInfo": "Community Information",
|
||||||
"contact": "Contact",
|
"contact": "Contact",
|
||||||
"contribution": {
|
"contribution": {
|
||||||
"activity": "Activity",
|
"activity": "Activity",
|
||||||
"alert": {
|
"alert": {
|
||||||
"answerQuestion": "Please answer the question",
|
"answerQuestion": "Please answer the question.",
|
||||||
|
"answerQuestionToast": "You have a question about a post. Please reply to it.",
|
||||||
"communityNoteList": "Here you will find all submitted and confirmed contributions from all members of this community.",
|
"communityNoteList": "Here you will find all submitted and confirmed contributions from all members of this community.",
|
||||||
"confirm": "confirmed",
|
"confirm": "confirmed",
|
||||||
|
"deleted": "deleted",
|
||||||
"in_progress": "There is a question from the moderators.",
|
"in_progress": "There is a question from the moderators.",
|
||||||
"myContributionNoteList": "You can edit or delete entries that have not yet been confirmed at any time.",
|
"myContributionNoteList": "You can edit or delete entries that have not yet been confirmed at any time.",
|
||||||
"pending": "Submitted and waiting for confirmation",
|
"pending": "Submitted and waiting for confirmation",
|
||||||
@ -47,7 +49,6 @@
|
|||||||
},
|
},
|
||||||
"delete": "Delete Contribution! Are you sure?",
|
"delete": "Delete Contribution! Are you sure?",
|
||||||
"deleted": "The contribution has been deleted! But it will remain visible.",
|
"deleted": "The contribution has been deleted! But it will remain visible.",
|
||||||
"exhausted": "You cannot create anything more for this month.",
|
|
||||||
"formText": {
|
"formText": {
|
||||||
"bringYourTalentsTo": "Bring your talents to the community! Your voluntary commitment will be rewarded with 20 GDD per hour up to a maximum of 1,000 GDD per month.",
|
"bringYourTalentsTo": "Bring your talents to the community! Your voluntary commitment will be rewarded with 20 GDD per hour up to a maximum of 1,000 GDD per month.",
|
||||||
"describeYourCommunity": "Describe your community service activity with hours and enter an amount of 20 GDD per hour! After confirmation by a moderator, the amount will be credited to your account.",
|
"describeYourCommunity": "Describe your community service activity with hours and enter an amount of 20 GDD per hour! After confirmation by a moderator, the amount will be credited to your account.",
|
||||||
@ -126,7 +127,7 @@
|
|||||||
"firstname": "Firstname",
|
"firstname": "Firstname",
|
||||||
"from": "from",
|
"from": "from",
|
||||||
"generate_now": "Generate now",
|
"generate_now": "Generate now",
|
||||||
"hours": "Horas",
|
"hours": "Hours",
|
||||||
"lastname": "Lastname",
|
"lastname": "Lastname",
|
||||||
"memo": "Message",
|
"memo": "Message",
|
||||||
"message": "Message",
|
"message": "Message",
|
||||||
@ -215,7 +216,6 @@
|
|||||||
},
|
},
|
||||||
"h": "h",
|
"h": "h",
|
||||||
"language": "Language",
|
"language": "Language",
|
||||||
"lastMonth": "Last month",
|
|
||||||
"link-load": "Load the last link | Load the last {n} links | Load more {n} links",
|
"link-load": "Load the last link | Load the last {n} links | Load more {n} links",
|
||||||
"login": "Sign in",
|
"login": "Sign in",
|
||||||
"math": {
|
"math": {
|
||||||
|
|||||||
@ -1,4 +1,6 @@
|
|||||||
{
|
{
|
||||||
|
"(": "(",
|
||||||
|
")": ")",
|
||||||
"100": "100%",
|
"100": "100%",
|
||||||
"1000thanks": "1000 mercis d'être avec nous!",
|
"1000thanks": "1000 mercis d'être avec nous!",
|
||||||
"125": "125%",
|
"125": "125%",
|
||||||
@ -20,25 +22,25 @@
|
|||||||
"community": {
|
"community": {
|
||||||
"choose-another-community": "Choisissez une autre communauté",
|
"choose-another-community": "Choisissez une autre communauté",
|
||||||
"community": "Communauté",
|
"community": "Communauté",
|
||||||
|
"communityMember": "Vous etes un membre actif",
|
||||||
"continue-to-registration": "Continuez l´inscription",
|
"continue-to-registration": "Continuez l´inscription",
|
||||||
"current-community": "Communauté actuelle",
|
|
||||||
"members": "Membres",
|
|
||||||
"moderator": "Modérateur",
|
"moderator": "Modérateur",
|
||||||
"moderators": "Modérateurs",
|
"moderators": "Modérateurs",
|
||||||
"myContributions": "Mes contributions aux biens communs",
|
"myContributions": "Mes contributions",
|
||||||
|
"noOpenContributionLinkText": "Currently there are no automatic creations.",
|
||||||
"openContributionLinks": "liste de liens de contribution publique",
|
"openContributionLinks": "liste de liens de contribution publique",
|
||||||
"openContributionLinkText": "Les {count} créations automatiques suivantes sont actuellement fournies par la communauté \"{name}\".",
|
"openContributionLinkText": "Les {count} créations automatiques suivantes sont actuellement fournies par la communauté \"{name}\".",
|
||||||
"other-communities": "Autres communautés",
|
"submitContribution": "Contribuer"
|
||||||
"statistic": "Statistiques",
|
|
||||||
"submitContribution": "écrire",
|
|
||||||
"switch-to-this-community": "Passer à cette communauté"
|
|
||||||
},
|
},
|
||||||
|
"communityInfo": "Information communauté^^",
|
||||||
|
"contact": "Contact",
|
||||||
"contribution": {
|
"contribution": {
|
||||||
"activity": "Activité",
|
"activity": "Activité",
|
||||||
"alert": {
|
"alert": {
|
||||||
"answerQuestion": "S'il te plais répond à la question",
|
"answerQuestion": "S'il te plais répond à la question",
|
||||||
"communityNoteList": "Vous trouverez ci-contre toutes les contributions versées et certifiées de tous les membres de cette communauté.",
|
"communityNoteList": "Vous trouverez ci-contre toutes les contributions versées et certifiées de tous les membres de cette communauté.",
|
||||||
"confirm": " Approuvé",
|
"confirm": "Approuvé",
|
||||||
|
"deleted": "Supprimé",
|
||||||
"in_progress": "Il y a une question du modérateur.",
|
"in_progress": "Il y a une question du modérateur.",
|
||||||
"myContributionNoteList": "À tout moment vous pouvez éditer ou supprimer les données qui n´ont pas été confirmées.",
|
"myContributionNoteList": "À tout moment vous pouvez éditer ou supprimer les données qui n´ont pas été confirmées.",
|
||||||
"pending": "Inscription en attente de validation",
|
"pending": "Inscription en attente de validation",
|
||||||
@ -65,6 +67,8 @@
|
|||||||
"thanksYouWith": "vous remercie avec",
|
"thanksYouWith": "vous remercie avec",
|
||||||
"unique": "(unique)"
|
"unique": "(unique)"
|
||||||
},
|
},
|
||||||
|
"contributionText": "Texte de la contribution",
|
||||||
|
"creation": "Création",
|
||||||
"decay": {
|
"decay": {
|
||||||
"before_startblock_transaction": "Cette transaction n´est pas péremptoire.",
|
"before_startblock_transaction": "Cette transaction n´est pas péremptoire.",
|
||||||
"calculation_decay": "Calcul de la décroissance",
|
"calculation_decay": "Calcul de la décroissance",
|
||||||
@ -84,6 +88,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"delete": "Supprimer",
|
"delete": "Supprimer",
|
||||||
|
"edit": "modifier",
|
||||||
"em-dash": "—",
|
"em-dash": "—",
|
||||||
"error": {
|
"error": {
|
||||||
"email-already-sent": "Nous vous avons déjà envoyé un email il y a moins de 10 minutes.",
|
"email-already-sent": "Nous vous avons déjà envoyé un email il y a moins de 10 minutes.",
|
||||||
@ -121,7 +126,7 @@
|
|||||||
"firstname": " Prénom",
|
"firstname": " Prénom",
|
||||||
"from": "de",
|
"from": "de",
|
||||||
"generate_now": "Produire maintenant",
|
"generate_now": "Produire maintenant",
|
||||||
"hours": "Uren",
|
"hours": "Heures",
|
||||||
"lastname": "Nom",
|
"lastname": "Nom",
|
||||||
"memo": "Note",
|
"memo": "Note",
|
||||||
"message": "Message",
|
"message": "Message",
|
||||||
@ -147,7 +152,8 @@
|
|||||||
"to": "à",
|
"to": "à",
|
||||||
"to1": "à",
|
"to1": "à",
|
||||||
"validation": {
|
"validation": {
|
||||||
"gddSendAmount": "L´espace {_field_} doit comprendre un nombre entre {min} et {max} avec un maximum de deux chiffres après la virgule",
|
"gddCreationTime": "Le champ {_field_} doit comprendre un nombre entre {min} et {max} avec un maximum de une décimale.",
|
||||||
|
"gddSendAmount": "Le champ {_field_} doit comprendre un nombre entre {min} et {max} avec un maximum de deux chiffres après la virgule",
|
||||||
"is-not": "Vous ne pouvez pas vous envoyer de Gradido à vous-même",
|
"is-not": "Vous ne pouvez pas vous envoyer de Gradido à vous-même",
|
||||||
"usernmae-regex": "Le nom d´utilisateur doit commencer par une lettre, suivi d´au moins deux caractères alphanumériques.",
|
"usernmae-regex": "Le nom d´utilisateur doit commencer par une lettre, suivi d´au moins deux caractères alphanumériques.",
|
||||||
"usernmae-unique": "Ce nom d´utilisateur est déjà pris."
|
"usernmae-unique": "Ce nom d´utilisateur est déjà pris."
|
||||||
@ -155,13 +161,13 @@
|
|||||||
"your_amount": "Votre montant"
|
"your_amount": "Votre montant"
|
||||||
},
|
},
|
||||||
"GDD": "GDD",
|
"GDD": "GDD",
|
||||||
|
"gddKonto": "Compte GDD",
|
||||||
"gdd_per_link": {
|
"gdd_per_link": {
|
||||||
"choose-amount": "Sélectionnez le montant que vous souhaitez envoyer via lien. Vous pouvez également joindre un message. Cliquez sur ‘créer maintenant’ pour établir un lien que vous pourrez partager.",
|
"choose-amount": "Sélectionnez le montant que vous souhaitez envoyer via lien. Vous pouvez également joindre un message. Cliquez sur ‘créer maintenant’ pour établir un lien que vous pourrez partager.",
|
||||||
"copy-link": "Copier le lien",
|
"copy-link": "Copier le lien",
|
||||||
"copy-link-with-text": "Copier le lien et le texte",
|
"copy-link-with-text": "Copier le lien et le texte",
|
||||||
"created": "Le lien a été créé!",
|
"created": "Le lien a été créé!",
|
||||||
"credit-your-gradido": "Pour l´accréditation du Gradido, cliquer sur le lien!",
|
"credit-your-gradido": "Pour l´accréditation du Gradido, cliquer sur le lien!",
|
||||||
"decay-14-day": "Perte sur 14 jours",
|
|
||||||
"delete-the-link": "Supprimer le lien?",
|
"delete-the-link": "Supprimer le lien?",
|
||||||
"deleted": "Le lien a été supprimé!",
|
"deleted": "Le lien a été supprimé!",
|
||||||
"expiredOn": "A expiré le",
|
"expiredOn": "A expiré le",
|
||||||
@ -188,6 +194,7 @@
|
|||||||
"validUntil": "Valide jusqu´au",
|
"validUntil": "Valide jusqu´au",
|
||||||
"validUntilDate": "Le lien est valide jusqu´au {date}."
|
"validUntilDate": "Le lien est valide jusqu´au {date}."
|
||||||
},
|
},
|
||||||
|
"GDT": "GDT",
|
||||||
"gdt": {
|
"gdt": {
|
||||||
"calculation": "Calcul de Gradido Transform",
|
"calculation": "Calcul de Gradido Transform",
|
||||||
"contribution": "Contribution",
|
"contribution": "Contribution",
|
||||||
@ -199,22 +206,25 @@
|
|||||||
"funding": "Aux contributions au financement",
|
"funding": "Aux contributions au financement",
|
||||||
"gdt": "Gradido Transform",
|
"gdt": "Gradido Transform",
|
||||||
"gdt-received": "Gradido Transform (GDT) perçu",
|
"gdt-received": "Gradido Transform (GDT) perçu",
|
||||||
|
"gdtKonto": "Compte GDT",
|
||||||
"no-transactions": "Vous ne possédez pas encore Gradido Transform (GDT).",
|
"no-transactions": "Vous ne possédez pas encore Gradido Transform (GDT).",
|
||||||
"not-reachable": "Le Serveur GDT n´est pas accessible.",
|
"not-reachable": "Le Serveur GDT n´est pas accessible.",
|
||||||
"publisher": "Un membre que vous avez référé a apporté un contribution",
|
"publisher": "Un membre que vous avez référé a apporté un contribution",
|
||||||
"raise": "Augmentation",
|
"raise": "Augmentation",
|
||||||
"recruited-member": "Membre invité"
|
"recruited-member": "Membre invité"
|
||||||
},
|
},
|
||||||
|
"h": "h",
|
||||||
"language": "Langage",
|
"language": "Langage",
|
||||||
"link-load": "Enregistrer le dernier lien | Enregistrer les derniers {n} liens | Enregistrer plus de {n} liens",
|
"link-load": "Enregistrer le dernier lien | Enregistrer les derniers {n} liens | Enregistrer plus de {n} liens",
|
||||||
"login": "Connexion",
|
"login": "Connexion",
|
||||||
"math": {
|
"math": {
|
||||||
"aprox": "~",
|
|
||||||
"asterisk": "*",
|
"asterisk": "*",
|
||||||
"equal": "=",
|
"equal": "=",
|
||||||
"minus": "−",
|
"minus": "−",
|
||||||
"pipe": "|"
|
"pipe": "|"
|
||||||
},
|
},
|
||||||
|
"maxReached": "Max. atteint",
|
||||||
|
"member": "Membre",
|
||||||
"message": {
|
"message": {
|
||||||
"activateEmail": "Votre compte n´a pas encore été activé. Veuillez vérifier vos emails et cliquer sur le lien d´activation ou faites la demande d´un nouveau lien en utilisant la page qui permet de générer un nouveau mot de passe.",
|
"activateEmail": "Votre compte n´a pas encore été activé. Veuillez vérifier vos emails et cliquer sur le lien d´activation ou faites la demande d´un nouveau lien en utilisant la page qui permet de générer un nouveau mot de passe.",
|
||||||
"checkEmail": "Votre email a bien été vérifié. Vous pouvez vous enregistrer maintenant.",
|
"checkEmail": "Votre email a bien été vérifié. Vous pouvez vous enregistrer maintenant.",
|
||||||
@ -231,13 +241,22 @@
|
|||||||
"community": "Communauté",
|
"community": "Communauté",
|
||||||
"info": "Information",
|
"info": "Information",
|
||||||
"logout": "Déconnexion",
|
"logout": "Déconnexion",
|
||||||
"members_area": "Partie réservée aux membres",
|
|
||||||
"overview": "Aperçu",
|
"overview": "Aperçu",
|
||||||
"profile": "Mon profile",
|
|
||||||
"send": "Envoyer",
|
"send": "Envoyer",
|
||||||
|
"settings": "Configuration",
|
||||||
"support": "Aide",
|
"support": "Aide",
|
||||||
"transactions": "Transactions"
|
"transactions": "Transactions"
|
||||||
},
|
},
|
||||||
|
"openHours": "Heures ouverte",
|
||||||
|
"pageTitle": {
|
||||||
|
"community": "Ma communauté",
|
||||||
|
"gdt": "Vos transactions GDT",
|
||||||
|
"information": "{community}",
|
||||||
|
"overview": "Bienvenue {name}",
|
||||||
|
"send": "Envoyé Gradidos",
|
||||||
|
"settings": "Configuration",
|
||||||
|
"transactions": "Vos transactions"
|
||||||
|
},
|
||||||
"qrCode": "QR Code",
|
"qrCode": "QR Code",
|
||||||
"send_gdd": "Envoyer GDD",
|
"send_gdd": "Envoyer GDD",
|
||||||
"send_per_link": "Envoyer GDD via lien",
|
"send_per_link": "Envoyer GDD via lien",
|
||||||
@ -248,6 +267,8 @@
|
|||||||
"warningText": "Êtes-vous toujours connecté?"
|
"warningText": "Êtes-vous toujours connecté?"
|
||||||
},
|
},
|
||||||
"settings": {
|
"settings": {
|
||||||
|
"hideAmountGDD": "Votre montant GDD est caché.",
|
||||||
|
"hideAmountGDT": "Votre montant GDT est caché.",
|
||||||
"language": {
|
"language": {
|
||||||
"changeLanguage": "Changer la langue",
|
"changeLanguage": "Changer la langue",
|
||||||
"de": "Deutsch",
|
"de": "Deutsch",
|
||||||
@ -280,7 +301,9 @@
|
|||||||
"text": "Sauvegardez votre nouveau mot de passe maintenant, que vous pourrez utiliser pour vous connecter à votre compte Gradido dans le futur."
|
"text": "Sauvegardez votre nouveau mot de passe maintenant, que vous pourrez utiliser pour vous connecter à votre compte Gradido dans le futur."
|
||||||
},
|
},
|
||||||
"subtitle": "Si vous avez oublié votre mot de passe, vous pouvez le réinitialiser ici."
|
"subtitle": "Si vous avez oublié votre mot de passe, vous pouvez le réinitialiser ici."
|
||||||
}
|
},
|
||||||
|
"showAmountGDD": "Votre montant GDD est visible.",
|
||||||
|
"showAmountGDT": "Votre montant GDT est visible."
|
||||||
},
|
},
|
||||||
"signin": "S´identifier",
|
"signin": "S´identifier",
|
||||||
"signup": "S´inscrire",
|
"signup": "S´inscrire",
|
||||||
@ -302,11 +325,8 @@
|
|||||||
"uppercase": "Une lettre majuscule requise."
|
"uppercase": "Une lettre majuscule requise."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"statistic": {
|
"status": "Statu",
|
||||||
"totalGradidoAvailable": "GDD total en circulation",
|
"submitted": "Envoyé",
|
||||||
"totalGradidoCreated": "GDD total puisé",
|
|
||||||
"totalGradidoDecayed": "Total de GDD écoulé"
|
|
||||||
},
|
|
||||||
"success": "Avec succès",
|
"success": "Avec succès",
|
||||||
"time": {
|
"time": {
|
||||||
"days": "Jours",
|
"days": "Jours",
|
||||||
@ -318,8 +338,7 @@
|
|||||||
"years": "Année"
|
"years": "Année"
|
||||||
},
|
},
|
||||||
"transaction": {
|
"transaction": {
|
||||||
"gdd-text": "Transactions Gradido",
|
"lastTransactions": "Dernières transactions",
|
||||||
"gdt-text": "Transactions de GradidoTransform",
|
|
||||||
"nullTransactions": "Vous n´avez pas encore de transaction effectuée sur votre compte.",
|
"nullTransactions": "Vous n´avez pas encore de transaction effectuée sur votre compte.",
|
||||||
"receiverDeleted": "Le compte du destinataire n´existe plus",
|
"receiverDeleted": "Le compte du destinataire n´existe plus",
|
||||||
"receiverNotFound": "Destinataire inconnu",
|
"receiverNotFound": "Destinataire inconnu",
|
||||||
|
|||||||
@ -24,15 +24,7 @@ export const copyLinks = {
|
|||||||
},
|
},
|
||||||
copyLinkWithText() {
|
copyLinkWithText() {
|
||||||
navigator.clipboard
|
navigator.clipboard
|
||||||
.writeText(
|
.writeText(this.linkText)
|
||||||
`${this.link}
|
|
||||||
${this.$store.state.firstName} ${this.$t('transaction-link.send_you')} ${this.amount} Gradido.
|
|
||||||
"${this.memo}"
|
|
||||||
${this.$t('gdd_per_link.credit-your-gradido')} ${this.$t('gdd_per_link.validUntilDate', {
|
|
||||||
date: this.$d(new Date(this.validUntil), 'short'),
|
|
||||||
})}
|
|
||||||
${this.$t('gdd_per_link.link-hint')}`,
|
|
||||||
)
|
|
||||||
.then(() => {
|
.then(() => {
|
||||||
this.toastSuccess(this.$t('gdd_per_link.link-and-text-copied'))
|
this.toastSuccess(this.$t('gdd_per_link.link-and-text-copied'))
|
||||||
})
|
})
|
||||||
@ -42,4 +34,15 @@ ${this.$t('gdd_per_link.link-hint')}`,
|
|||||||
})
|
})
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
computed: {
|
||||||
|
linkText() {
|
||||||
|
return `${this.link}
|
||||||
|
${this.$store.state.firstName} ${this.$t('transaction-link.send_you')} ${this.amount} Gradido.
|
||||||
|
"${this.memo}"
|
||||||
|
${this.$t('gdd_per_link.credit-your-gradido')} ${this.$t('gdd_per_link.validUntilDate', {
|
||||||
|
date: this.$d(new Date(this.validUntil), 'short'),
|
||||||
|
})}
|
||||||
|
${this.$t('gdd_per_link.link-hint')}`
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@ -284,13 +284,6 @@ describe('Community', () => {
|
|||||||
it('verifies the login (to get the new creations available)', () => {
|
it('verifies the login (to get the new creations available)', () => {
|
||||||
expect(apolloRefetchMock).toBeCalled()
|
expect(apolloRefetchMock).toBeCalled()
|
||||||
})
|
})
|
||||||
|
|
||||||
it('set all data to the default values)', () => {
|
|
||||||
expect(wrapper.vm.form.id).toBe(null)
|
|
||||||
expect(wrapper.vm.form.date).toBe('')
|
|
||||||
expect(wrapper.vm.form.memo).toBe('')
|
|
||||||
expect(wrapper.vm.form.amount).toBe('')
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('with error', () => {
|
describe('with error', () => {
|
||||||
|
|||||||
@ -118,7 +118,7 @@ export default {
|
|||||||
if (num !== 0) {
|
if (num !== 0) {
|
||||||
this.form = {
|
this.form = {
|
||||||
id: null,
|
id: null,
|
||||||
date: '',
|
date: new Date(),
|
||||||
memo: '',
|
memo: '',
|
||||||
hours: 0,
|
hours: 0,
|
||||||
amount: '',
|
amount: '',
|
||||||
@ -282,7 +282,7 @@ export default {
|
|||||||
if (this.$route.hash !== '#my') {
|
if (this.$route.hash !== '#my') {
|
||||||
this.$router.push({ path: '/community#my' })
|
this.$router.push({ path: '/community#my' })
|
||||||
}
|
}
|
||||||
this.toastInfo('Du hast eine Rückfrage auf eine Contribution. Bitte beantworte diese!')
|
this.toastInfo(this.$t('contribution.alert.answerQuestionToast'))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { mount, RouterLinkStub } from '@vue/test-utils'
|
import { mount } from '@vue/test-utils'
|
||||||
import flushPromises from 'flush-promises'
|
import flushPromises from 'flush-promises'
|
||||||
import { toastErrorSpy } from '@test/testSetup'
|
import { toastErrorSpy } from '@test/testSetup'
|
||||||
import ForgotPassword from './ForgotPassword'
|
import ForgotPassword from './ForgotPassword'
|
||||||
@ -7,43 +7,28 @@ const mockAPIcall = jest.fn()
|
|||||||
|
|
||||||
const localVue = global.localVue
|
const localVue = global.localVue
|
||||||
|
|
||||||
const mockRouterPush = jest.fn()
|
const mocks = {
|
||||||
|
$t: jest.fn((t) => t),
|
||||||
const stubs = {
|
$apollo: {
|
||||||
RouterLink: RouterLinkStub,
|
mutate: mockAPIcall,
|
||||||
}
|
},
|
||||||
|
$route: {
|
||||||
const createMockObject = (comingFrom) => {
|
params: {
|
||||||
return {
|
comingFrom: '',
|
||||||
localVue,
|
|
||||||
mocks: {
|
|
||||||
$t: jest.fn((t) => t),
|
|
||||||
$router: {
|
|
||||||
push: mockRouterPush,
|
|
||||||
},
|
|
||||||
$apollo: {
|
|
||||||
mutate: mockAPIcall,
|
|
||||||
},
|
|
||||||
$route: {
|
|
||||||
params: {
|
|
||||||
comingFrom,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
stubs,
|
},
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
describe('ForgotPassword', () => {
|
describe('ForgotPassword', () => {
|
||||||
let wrapper
|
let wrapper
|
||||||
|
|
||||||
const Wrapper = (functionN) => {
|
const Wrapper = () => {
|
||||||
return mount(ForgotPassword, functionN)
|
return mount(ForgotPassword, { localVue, mocks })
|
||||||
}
|
}
|
||||||
|
|
||||||
describe('mount', () => {
|
describe('mount', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
wrapper = Wrapper(createMockObject())
|
wrapper = Wrapper()
|
||||||
})
|
})
|
||||||
|
|
||||||
it('renders the component', () => {
|
it('renders the component', () => {
|
||||||
@ -110,12 +95,6 @@ describe('ForgotPassword', () => {
|
|||||||
expect(wrapper.find('.test-message-button').attributes('href')).toBe('/login')
|
expect(wrapper.find('.test-message-button').attributes('href')).toBe('/login')
|
||||||
})
|
})
|
||||||
|
|
||||||
it.skip('click redirects to "/login"', async () => {
|
|
||||||
// wrapper.find('.test-message-button').trigger('click')
|
|
||||||
// await wrapper.vm.$nextTick()
|
|
||||||
expect(mockRouterPush).toBeCalledWith('/login')
|
|
||||||
})
|
|
||||||
|
|
||||||
it('toasts a standard error message', () => {
|
it('toasts a standard error message', () => {
|
||||||
expect(toastErrorSpy).toBeCalledWith('error.email-already-sent')
|
expect(toastErrorSpy).toBeCalledWith('error.email-already-sent')
|
||||||
})
|
})
|
||||||
@ -144,13 +123,20 @@ describe('ForgotPassword', () => {
|
|||||||
it('button link redirects to "/login"', () => {
|
it('button link redirects to "/login"', () => {
|
||||||
expect(wrapper.find('.test-message-button').attributes('href')).toBe('/login')
|
expect(wrapper.find('.test-message-button').attributes('href')).toBe('/login')
|
||||||
})
|
})
|
||||||
|
|
||||||
it.skip('click redirects to "/login"', () => {
|
|
||||||
// expect(mockRouterPush).toBeCalledWith('/login')
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('route has coming from ', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
mocks.$route.params.comingFrom = 'coming from'
|
||||||
|
wrapper = Wrapper()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('changes subtitle', () => {
|
||||||
|
expect(wrapper.vm.subtitle).toBe('settings.password.resend_subtitle')
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@ -254,7 +254,7 @@ describe('Send', () => {
|
|||||||
describe('copy link with success', () => {
|
describe('copy link with success', () => {
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
navigatorClipboardMock.mockResolvedValue()
|
navigatorClipboardMock.mockResolvedValue()
|
||||||
await wrapper.find('.pointer').trigger('click')
|
await wrapper.find('div[data-test="copyLink"]').trigger('click')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should call clipboard.writeText', () => {
|
it('should call clipboard.writeText', () => {
|
||||||
@ -270,7 +270,7 @@ describe('Send', () => {
|
|||||||
describe('copy link with error', () => {
|
describe('copy link with error', () => {
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
navigatorClipboardMock.mockRejectedValue()
|
navigatorClipboardMock.mockRejectedValue()
|
||||||
await wrapper.find('.clipboard-copy').find('.btn-secondary').trigger('click')
|
await wrapper.find('div[data-test="copyLink"]').trigger('click')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('toasts error message', () => {
|
it('toasts error message', () => {
|
||||||
@ -292,7 +292,7 @@ describe('Send', () => {
|
|||||||
describe('copy link and text with success', () => {
|
describe('copy link and text with success', () => {
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
navigatorClipboardMock.mockResolvedValue()
|
navigatorClipboardMock.mockResolvedValue()
|
||||||
await wrapper.findAll('button').at(0).trigger('click')
|
await wrapper.find('div[data-test="copyLinkWithText"]').trigger('click')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should call clipboard.writeText', () => {
|
it('should call clipboard.writeText', () => {
|
||||||
@ -312,7 +312,7 @@ describe('Send', () => {
|
|||||||
describe('copy link and text with error', () => {
|
describe('copy link and text with error', () => {
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
navigatorClipboardMock.mockRejectedValue()
|
navigatorClipboardMock.mockRejectedValue()
|
||||||
await wrapper.findAll('button').at(0).trigger('click')
|
await wrapper.find('div[data-test="copyLinkWithText"]').trigger('click')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('toasts error message', () => {
|
it('toasts error message', () => {
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<gdd-send :currentTransactionStep="currentTransactionStep" class="pt-3 mt--3">
|
<gdd-send :currentTransactionStep="currentTransactionStep">
|
||||||
<template #transactionForm>
|
<template #transactionForm>
|
||||||
<transaction-form
|
<transaction-form
|
||||||
v-bind="transactionData"
|
v-bind="transactionData"
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="container bg-white appBoxShadow gradido-border-radius p-3 mt--3">
|
<div class="container bg-white appBoxShadow p-3 mt--3">
|
||||||
<user-card :balance="balance" :transactionCount="transactionCount"></user-card>
|
<user-card :balance="balance" :transactionCount="transactionCount"></user-card>
|
||||||
<user-data />
|
<user-data />
|
||||||
<hr />
|
<hr />
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
import { mount } from '@vue/test-utils'
|
import { mount } from '@vue/test-utils'
|
||||||
import Transactions from './Transactions'
|
import Transactions from './Transactions'
|
||||||
import { GdtEntryType } from '@/graphql/enums'
|
import { GdtEntryType } from '@/graphql/enums'
|
||||||
|
import { listGDTEntriesQuery } from '@/graphql/queries'
|
||||||
|
|
||||||
import { toastErrorSpy } from '@test/testSetup'
|
import { toastErrorSpy } from '@test/testSetup'
|
||||||
|
|
||||||
@ -45,8 +46,8 @@ describe('Transactions', () => {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
const Wrapper = () => {
|
const Wrapper = (propsData = {}) => {
|
||||||
return mount(Transactions, { localVue, mocks })
|
return mount(Transactions, { localVue, mocks, propsData })
|
||||||
}
|
}
|
||||||
|
|
||||||
describe('mount', () => {
|
describe('mount', () => {
|
||||||
@ -77,147 +78,111 @@ describe('Transactions', () => {
|
|||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
it.skip('renders the transaction gradido transform table', () => {
|
it('renders the transaction gradido transform table when gdt is true', async () => {
|
||||||
beforeEach(() => {
|
await wrapper.setProps({
|
||||||
wrapper.setData({
|
gdt: true,
|
||||||
gdt: true,
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
expect(wrapper.findComponent({ name: 'GdtTransactionList' }).exists()).toBeTruthy()
|
expect(wrapper.findComponent({ name: 'GdtTransactionList' }).exists()).toBeTruthy()
|
||||||
})
|
})
|
||||||
|
|
||||||
describe.skip('tabs', () => {
|
describe('update gdt with success', () => {
|
||||||
it('shows the GDD transactions by default', () => {
|
|
||||||
expect(wrapper.findAll('div[role="tabpanel"]').at(0).isVisible()).toBeTruthy()
|
|
||||||
})
|
|
||||||
|
|
||||||
it('does not show the GDT transactions by default', () => {
|
|
||||||
expect(wrapper.findAll('div[role="tabpanel"]').at(1).isVisible()).toBeFalsy()
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('click on GDT tab', () => {
|
|
||||||
describe('server returns valid data', () => {
|
|
||||||
beforeEach(() => {
|
|
||||||
apolloMock.mockResolvedValue({
|
|
||||||
data: {
|
|
||||||
listGDTEntries: {
|
|
||||||
count: 4,
|
|
||||||
gdtEntries: [
|
|
||||||
{
|
|
||||||
id: 1,
|
|
||||||
amount: 100,
|
|
||||||
gdt: 1700,
|
|
||||||
factor: 17,
|
|
||||||
comment: '',
|
|
||||||
date: '2021-05-02T17:20:11+00:00',
|
|
||||||
gdtEntryType: GdtEntryType.FORM,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 2,
|
|
||||||
amount: 1810,
|
|
||||||
gdt: 362,
|
|
||||||
factor: 0.2,
|
|
||||||
comment: 'Dezember 20',
|
|
||||||
date: '2020-12-31T12:00:00+00:00',
|
|
||||||
gdtEntryType: GdtEntryType.GLOBAL_MODIFICATOR,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 3,
|
|
||||||
amount: 100,
|
|
||||||
gdt: 1700,
|
|
||||||
factor: 17,
|
|
||||||
comment: '',
|
|
||||||
date: '2020-05-07T17:00:00+00:00',
|
|
||||||
gdtEntryType: GdtEntryType.FORM,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 4,
|
|
||||||
amount: 100,
|
|
||||||
gdt: 110,
|
|
||||||
factor: 22,
|
|
||||||
comment: '',
|
|
||||||
date: '2020-04-10T13:28:00+00:00',
|
|
||||||
gdtEntryType: GdtEntryType.ELOPAGE_PUBLISHER,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
wrapper.findAll('li[ role="presentation"]').at(1).find('a').trigger('click')
|
|
||||||
})
|
|
||||||
|
|
||||||
it('does not show the GDD transactions', () => {
|
|
||||||
expect(wrapper.findAll('div[role="tabpanel"]').at(0).isVisible()).toBeFalsy()
|
|
||||||
})
|
|
||||||
|
|
||||||
it('shows the GDT transactions', () => {
|
|
||||||
expect(wrapper.findAll('div[role="tabpanel"]').at(1).isVisible()).toBeTruthy()
|
|
||||||
})
|
|
||||||
|
|
||||||
it('calls the API', () => {
|
|
||||||
expect(apolloMock).toBeCalledWith(
|
|
||||||
expect.objectContaining({
|
|
||||||
variables: {
|
|
||||||
currentPage: 1,
|
|
||||||
pageSize: 25,
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('scrolls to (0, 0) after API call', () => {
|
|
||||||
expect(windowScrollToMock).toBeCalledWith(0, 0)
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('click on GDD tab', () => {
|
|
||||||
beforeEach(() => {
|
|
||||||
wrapper.findAll('li[ role="presentation"]').at(0).find('a').trigger('click')
|
|
||||||
})
|
|
||||||
|
|
||||||
it('shows the GDD transactions', () => {
|
|
||||||
expect(wrapper.findAll('div[role="tabpanel"]').at(0).isVisible()).toBeTruthy()
|
|
||||||
})
|
|
||||||
|
|
||||||
it('does not show the GDT', () => {
|
|
||||||
expect(wrapper.findAll('div[role="tabpanel"]').at(1).isVisible()).toBeFalsy()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('server returns error', () => {
|
|
||||||
beforeEach(() => {
|
|
||||||
apolloMock.mockRejectedValue({ message: 'Ouch!' })
|
|
||||||
wrapper.findAll('li[ role="presentation"]').at(1).find('a').trigger('click')
|
|
||||||
})
|
|
||||||
|
|
||||||
it('toasts an error message', () => {
|
|
||||||
expect(toastErrorSpy).toBeCalledWith('Ouch!')
|
|
||||||
})
|
|
||||||
|
|
||||||
it('sets transactionGdtCount to -1', () => {
|
|
||||||
expect(wrapper.vm.transactionGdtCount).toBe(-1)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
describe.skip('update currentPage', () => {
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
jest.clearAllMocks()
|
apolloMock.mockResolvedValue({
|
||||||
wrapper.setData({
|
data: {
|
||||||
currentPage: 2,
|
listGDTEntries: {
|
||||||
|
count: 4,
|
||||||
|
gdtEntries: [
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
amount: 100,
|
||||||
|
gdt: 1700,
|
||||||
|
factor: 17,
|
||||||
|
comment: '',
|
||||||
|
date: '2021-05-02T17:20:11+00:00',
|
||||||
|
gdtEntryType: GdtEntryType.FORM,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 2,
|
||||||
|
amount: 1810,
|
||||||
|
gdt: 362,
|
||||||
|
factor: 0.2,
|
||||||
|
comment: 'Dezember 20',
|
||||||
|
date: '2020-12-31T12:00:00+00:00',
|
||||||
|
gdtEntryType: GdtEntryType.GLOBAL_MODIFICATOR,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 3,
|
||||||
|
amount: 100,
|
||||||
|
gdt: 1700,
|
||||||
|
factor: 17,
|
||||||
|
comment: '',
|
||||||
|
date: '2020-05-07T17:00:00+00:00',
|
||||||
|
gdtEntryType: GdtEntryType.FORM,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 4,
|
||||||
|
amount: 100,
|
||||||
|
gdt: 110,
|
||||||
|
factor: 22,
|
||||||
|
comment: '',
|
||||||
|
date: '2020-04-10T13:28:00+00:00',
|
||||||
|
gdtEntryType: GdtEntryType.ELOPAGE_PUBLISHER,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
})
|
})
|
||||||
|
wrapper = Wrapper({ gdt: true })
|
||||||
})
|
})
|
||||||
|
|
||||||
it('calls the API', () => {
|
it('calls the API', () => {
|
||||||
expect(apolloMock).toBeCalledWith(
|
expect(apolloMock).toBeCalledWith({
|
||||||
expect.objectContaining({
|
query: listGDTEntriesQuery,
|
||||||
|
variables: {
|
||||||
|
currentPage: 1,
|
||||||
|
pageSize: 25,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('does not show the GDD transactions', () => {
|
||||||
|
expect(wrapper.findAll('div.gdd-transaction-list').exists()).toBeFalsy()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('shows the GDT transactions', () => {
|
||||||
|
expect(wrapper.findAll('div.gdt-transaction-list').exists()).toBeTruthy()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('scrolls to (0, 0) after API call', () => {
|
||||||
|
expect(windowScrollToMock).toBeCalledWith(0, 0)
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('update current page', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
jest.clearAllMocks()
|
||||||
|
wrapper.vm.currentPage = 2
|
||||||
|
})
|
||||||
|
|
||||||
|
it('calls the API again', () => {
|
||||||
|
expect(apolloMock).toBeCalledWith({
|
||||||
|
query: listGDTEntriesQuery,
|
||||||
variables: {
|
variables: {
|
||||||
currentPage: 2,
|
currentPage: 2,
|
||||||
pageSize: 25,
|
pageSize: 25,
|
||||||
},
|
},
|
||||||
}),
|
})
|
||||||
)
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('update gdt with error', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
apolloMock.mockRejectedValue({ message: 'Oh no!' })
|
||||||
|
wrapper = Wrapper({ gdt: true })
|
||||||
|
})
|
||||||
|
|
||||||
|
it('toasts the error', () => {
|
||||||
|
expect(toastErrorSpy).toBeCalledWith('Oh no!')
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@ -15,6 +15,7 @@
|
|||||||
:transactionLinkCount="transactionLinkCount"
|
:transactionLinkCount="transactionLinkCount"
|
||||||
:transactions="transactions"
|
:transactions="transactions"
|
||||||
:showPagination="true"
|
:showPagination="true"
|
||||||
|
:pageSize="pageSize"
|
||||||
@update-transactions="updateTransactions"
|
@update-transactions="updateTransactions"
|
||||||
v-on="$listeners"
|
v-on="$listeners"
|
||||||
/>
|
/>
|
||||||
@ -90,6 +91,11 @@ export default {
|
|||||||
this.updateGdt()
|
this.updateGdt()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
gdt() {
|
||||||
|
if (this.gdt) {
|
||||||
|
this.updateGdt()
|
||||||
|
}
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -56,7 +56,6 @@ export const loadAllRules = (i18nCallback) => {
|
|||||||
|
|
||||||
extend('gddCreationTime', {
|
extend('gddCreationTime', {
|
||||||
validate(value, { min, max }) {
|
validate(value, { min, max }) {
|
||||||
if (value) value = value.replace(',', '.')
|
|
||||||
return value >= min && value <= max
|
return value >= min && value <= max
|
||||||
},
|
},
|
||||||
params: ['min', 'max'],
|
params: ['min', 'max'],
|
||||||
|
|||||||
@ -70,6 +70,6 @@ console.warn = (m) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// throw errors for vue warnings to force the programmers to take care about warnings
|
// throw errors for vue warnings to force the programmers to take care about warnings
|
||||||
Vue.config.warnHandler = (w) => {
|
Vue.config.warnHandler = async (w) => {
|
||||||
throw new Error(w)
|
throw new Error(w)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "gradido",
|
"name": "gradido",
|
||||||
"version": "1.16.0",
|
"version": "1.17.1",
|
||||||
"description": "Gradido",
|
"description": "Gradido",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"repository": "git@github.com:gradido/gradido.git",
|
"repository": "git@github.com:gradido/gradido.git",
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user