diff --git a/admin/package.json b/admin/package.json
index ae1f1c305..3d3919954 100644
--- a/admin/package.json
+++ b/admin/package.json
@@ -14,7 +14,7 @@
"analyse-bundle": "yarn build && webpack-bundle-analyzer dist/webpack.stats.json",
"lint": "eslint --max-warnings=0 --ext .js,.vue,.json .",
"stylelint": "stylelint --max-warnings=0 '**/*.{scss,vue}'",
- "test": "TZ=UTC jest --coverage",
+ "test": "cross-env TZ=UTC jest --coverage",
"locales": "scripts/sort.sh"
},
"dependencies": {
@@ -57,6 +57,7 @@
"@vue/cli-service": "~4.5.0",
"babel-eslint": "^10.1.0",
"babel-plugin-transform-require-context": "^0.1.1",
+ "cross-env": "^7.0.3",
"eslint": "7.25.0",
"eslint-config-prettier": "^8.3.0",
"eslint-config-standard": "^16.0.3",
diff --git a/admin/yarn.lock b/admin/yarn.lock
index d5fae27fe..af1d18fa6 100644
--- a/admin/yarn.lock
+++ b/admin/yarn.lock
@@ -4688,6 +4688,13 @@ create-hmac@^1.1.0, create-hmac@^1.1.4, create-hmac@^1.1.7:
safe-buffer "^5.0.1"
sha.js "^2.4.8"
+cross-env@^7.0.3:
+ version "7.0.3"
+ resolved "https://registry.yarnpkg.com/cross-env/-/cross-env-7.0.3.tgz#865264b29677dc015ba8418918965dd232fc54cf"
+ integrity sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==
+ dependencies:
+ cross-spawn "^7.0.1"
+
cross-spawn@^5.0.1:
version "5.1.0"
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449"
@@ -4708,7 +4715,7 @@ cross-spawn@^6.0.0:
shebang-command "^1.2.0"
which "^1.2.9"
-cross-spawn@^7.0.0, cross-spawn@^7.0.2:
+cross-spawn@^7.0.0, cross-spawn@^7.0.1, cross-spawn@^7.0.2:
version "7.0.3"
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6"
integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==
diff --git a/backend/.env.dist b/backend/.env.dist
index b0a08753c..de33a7272 100644
--- a/backend/.env.dist
+++ b/backend/.env.dist
@@ -1,4 +1,4 @@
-CONFIG_VERSION=v5.2022-04-12
+CONFIG_VERSION=v6.2022-04-21
# Server
PORT=4000
@@ -27,6 +27,7 @@ KLICKTIPP_APIKEY_EN=SomeFakeKeyEN
COMMUNITY_NAME=Gradido Entwicklung
COMMUNITY_URL=http://localhost/
COMMUNITY_REGISTER_URL=http://localhost/register
+COMMUNITY_REDEEM_URL=http://localhost/redeem/{code}
COMMUNITY_DESCRIPTION=Die lokale Entwicklungsumgebung von Gradido.
# Login Server
diff --git a/backend/.env.template b/backend/.env.template
index 5da108f53..8ce8fca4e 100644
--- a/backend/.env.template
+++ b/backend/.env.template
@@ -26,6 +26,7 @@ KLICKTIPP_APIKEY_EN=$KLICKTIPP_APIKEY_EN
COMMUNITY_NAME=$COMMUNITY_NAME
COMMUNITY_URL=$COMMUNITY_URL
COMMUNITY_REGISTER_URL=$COMMUNITY_REGISTER_URL
+COMMUNITY_REDEEM_URL=$COMMUNITY_REDEEM_URL
COMMUNITY_DESCRIPTION=$COMMUNITY_DESCRIPTION
# Login Server
diff --git a/backend/package.json b/backend/package.json
index 3c4066d6b..8654f4cc7 100644
--- a/backend/package.json
+++ b/backend/package.json
@@ -10,11 +10,11 @@
"scripts": {
"build": "tsc --build",
"clean": "tsc --build --clean",
- "start": "TZ=UTC TS_NODE_BASEURL=./build node -r tsconfig-paths/register build/src/index.js",
- "dev": "TZ=UTC nodemon -w src --ext ts --exec ts-node -r tsconfig-paths/register src/index.ts",
+ "start": "cross-env TZ=UTC TS_NODE_BASEURL=./build node -r tsconfig-paths/register build/src/index.js",
+ "dev": "cross-env TZ=UTC nodemon -w src --ext ts --exec ts-node -r tsconfig-paths/register src/index.ts",
"lint": "eslint --max-warnings=0 --ext .js,.ts .",
- "test": "TZ=UTC NODE_ENV=development jest --runInBand --coverage --forceExit --detectOpenHandles",
- "seed": "TZ=UTC ts-node -r tsconfig-paths/register src/seeds/index.ts"
+ "test": "cross-env TZ=UTC NODE_ENV=development jest --runInBand --coverage --forceExit --detectOpenHandles",
+ "seed": "cross-env TZ=UTC ts-node -r tsconfig-paths/register src/seeds/index.ts"
},
"dependencies": {
"@types/jest": "^27.0.2",
@@ -25,6 +25,7 @@
"axios": "^0.21.1",
"class-validator": "^0.13.1",
"cors": "^2.8.5",
+ "cross-env": "^7.0.3",
"decimal.js-light": "^2.5.1",
"dotenv": "^10.0.0",
"express": "^4.17.1",
diff --git a/backend/src/config/index.ts b/backend/src/config/index.ts
index 1f134f23d..868a43f5a 100644
--- a/backend/src/config/index.ts
+++ b/backend/src/config/index.ts
@@ -14,7 +14,7 @@ const constants = {
DECAY_START_TIME: new Date('2021-05-13 17:46:31'), // GMT+0
CONFIG_VERSION: {
DEFAULT: 'DEFAULT',
- EXPECTED: 'v5.2022-04-12',
+ EXPECTED: 'v6.2022-04-21',
CURRENT: '',
},
}
@@ -50,6 +50,7 @@ const community = {
COMMUNITY_NAME: process.env.COMMUNITY_NAME || 'Gradido Entwicklung',
COMMUNITY_URL: process.env.COMMUNITY_URL || 'http://localhost/',
COMMUNITY_REGISTER_URL: process.env.COMMUNITY_REGISTER_URL || 'http://localhost/register',
+ COMMUNITY_REDEEM_URL: process.env.COMMUNITY_REDEEM_URL || 'http://localhost/redeem/{code}',
COMMUNITY_DESCRIPTION:
process.env.COMMUNITY_DESCRIPTION || 'Die lokale Entwicklungsumgebung von Gradido.',
}
diff --git a/backend/src/graphql/model/TransactionLink.ts b/backend/src/graphql/model/TransactionLink.ts
index 5081ffd7d..18a601948 100644
--- a/backend/src/graphql/model/TransactionLink.ts
+++ b/backend/src/graphql/model/TransactionLink.ts
@@ -2,6 +2,7 @@ import { ObjectType, Field, Int } from 'type-graphql'
import Decimal from 'decimal.js-light'
import { TransactionLink as dbTransactionLink } from '@entity/TransactionLink'
import { User } from './User'
+import CONFIG from '@/config'
@ObjectType()
export class TransactionLink {
@@ -17,6 +18,7 @@ export class TransactionLink {
this.deletedAt = transactionLink.deletedAt
this.redeemedAt = transactionLink.redeemedAt
this.redeemedBy = redeemedBy
+ this.link = CONFIG.COMMUNITY_REDEEM_URL.replace(/{code}/g, this.code)
}
@Field(() => Number)
@@ -51,6 +53,9 @@ export class TransactionLink {
@Field(() => User, { nullable: true })
redeemedBy: User | null
+
+ @Field(() => String)
+ link: string
}
@ObjectType()
diff --git a/backend/yarn.lock b/backend/yarn.lock
index 3ba20211a..f37b64d11 100644
--- a/backend/yarn.lock
+++ b/backend/yarn.lock
@@ -1900,7 +1900,14 @@ create-require@^1.1.0:
resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333"
integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==
-cross-spawn@^7.0.2, cross-spawn@^7.0.3:
+cross-env@^7.0.3:
+ version "7.0.3"
+ resolved "https://registry.yarnpkg.com/cross-env/-/cross-env-7.0.3.tgz#865264b29677dc015ba8418918965dd232fc54cf"
+ integrity sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==
+ dependencies:
+ cross-spawn "^7.0.1"
+
+cross-spawn@^7.0.1, cross-spawn@^7.0.2, cross-spawn@^7.0.3:
version "7.0.3"
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6"
integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==
diff --git a/database/package.json b/database/package.json
index 40c43c9b5..a1fffa882 100644
--- a/database/package.json
+++ b/database/package.json
@@ -10,15 +10,15 @@
"scripts": {
"build": "mkdir -p build/src/config/ && cp src/config/*.txt build/src/config/ && tsc --build",
"clean": "tsc --build --clean",
- "up": "TZ=UTC node build/src/index.js up",
- "down": "TZ=UTC node build/src/index.js down",
- "reset": "TZ=UTC node build/src/index.js reset",
- "dev_up": "TZ=UTC ts-node src/index.ts up",
- "dev_down": "TZ=UTC ts-node src/index.ts down",
- "dev_reset": "TZ=UTC ts-node src/index.ts reset",
+ "up": "cross-env TZ=UTC node build/src/index.js up",
+ "down": "cross-env TZ=UTC node build/src/index.js down",
+ "reset": "cross-env TZ=UTC node build/src/index.js reset",
+ "dev_up": "cross-env TZ=UTC ts-node src/index.ts up",
+ "dev_down": "cross-env TZ=UTC ts-node src/index.ts down",
+ "dev_reset": "cross-env TZ=UTC ts-node src/index.ts reset",
"lint": "eslint --max-warnings=0 --ext .js,.ts .",
"seed:config": "ts-node ./node_modules/typeorm-seeding/dist/cli.js config",
- "seed": "TZ=UTC ts-node src/index.ts seed"
+ "seed": "cross-env TZ=UTC ts-node src/index.ts seed"
},
"devDependencies": {
"@types/faker": "^5.5.9",
@@ -37,6 +37,7 @@
"typescript": "^4.3.5"
},
"dependencies": {
+ "cross-env": "^7.0.3",
"crypto": "^1.0.1",
"decimal.js-light": "^2.5.1",
"dotenv": "^10.0.0",
diff --git a/database/yarn.lock b/database/yarn.lock
index a2df693ec..e5d74929c 100644
--- a/database/yarn.lock
+++ b/database/yarn.lock
@@ -481,7 +481,14 @@ create-require@^1.1.0:
resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333"
integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==
-cross-spawn@^7.0.2:
+cross-env@^7.0.3:
+ version "7.0.3"
+ resolved "https://registry.yarnpkg.com/cross-env/-/cross-env-7.0.3.tgz#865264b29677dc015ba8418918965dd232fc54cf"
+ integrity sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==
+ dependencies:
+ cross-spawn "^7.0.1"
+
+cross-spawn@^7.0.1, cross-spawn@^7.0.2:
version "7.0.3"
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6"
integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==
diff --git a/deployment/bare_metal/.env.dist b/deployment/bare_metal/.env.dist
index efac0fc68..316fb60c2 100644
--- a/deployment/bare_metal/.env.dist
+++ b/deployment/bare_metal/.env.dist
@@ -24,7 +24,7 @@ COMMUNITY_REGISTER_URL=https://stage1.gradido.net/register
COMMUNITY_DESCRIPTION="Gradido Development Stage1 Test Community"
# backend
-BACKEND_CONFIG_VERSION=v5.2022-04-12
+BACKEND_CONFIG_VERSION=v6.2022-04-21
JWT_EXPIRES_IN=30m
GDT_API_URL=https://gdt.gradido.net
diff --git a/docu/graphics/federation.drawio b/docu/graphics/federation.drawio
new file mode 100644
index 000000000..1b4db9002
--- /dev/null
+++ b/docu/graphics/federation.drawio
@@ -0,0 +1,135 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/docu/graphics/federation.png b/docu/graphics/federation.png
new file mode 100644
index 000000000..6d25708f8
Binary files /dev/null and b/docu/graphics/federation.png differ
diff --git a/frontend/package.json b/frontend/package.json
index 3bd975798..b3091d4b4 100755
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -10,7 +10,7 @@
"analyse-bundle": "yarn build && webpack-bundle-analyzer dist/webpack.stats.json",
"lint": "eslint --max-warnings=0 --ext .js,.vue,.json .",
"stylelint": "stylelint --max-warnings=0 '**/*.{scss,vue}'",
- "test": "TZ=UTC jest --coverage",
+ "test": "cross-env TZ=UTC jest --coverage",
"locales": "scripts/sort.sh"
},
"dependencies": {
@@ -72,6 +72,7 @@
"babel-eslint": "^10.1.0",
"babel-plugin-component": "^1.1.0",
"babel-plugin-transform-require-context": "^0.1.1",
+ "cross-env": "^7.0.3",
"dotenv-webpack": "^7.0.3",
"postcss": "^8.4.8",
"postcss-html": "^1.3.0",
diff --git a/frontend/src/components/ClipboardCopy.vue b/frontend/src/components/ClipboardCopy.vue
index 810f73fe1..936f6db1a 100644
--- a/frontend/src/components/ClipboardCopy.vue
+++ b/frontend/src/components/ClipboardCopy.vue
@@ -1,11 +1,14 @@
-
+
-
+
{{ $t('gdd_per_link.copy') }}
+
+
+
@@ -14,12 +17,12 @@
export default {
name: 'ClipboardCopy',
props: {
- text: { type: String, required: true },
+ link: { type: String, required: true },
},
methods: {
CopyLink() {
navigator.clipboard
- .writeText(this.url)
+ .writeText(this.link)
.then(() => {
this.toastSuccess(this.$t('gdd_per_link.link-copied'))
})
@@ -30,3 +33,8 @@ export default {
},
}
+
diff --git a/frontend/src/components/DecayInformations/CollapseLinksList.spec.js b/frontend/src/components/DecayInformations/CollapseLinksList.spec.js
index 4fc527e39..68d5d427f 100644
--- a/frontend/src/components/DecayInformations/CollapseLinksList.spec.js
+++ b/frontend/src/components/DecayInformations/CollapseLinksList.spec.js
@@ -17,6 +17,7 @@ const propsData = {
{
amount: '5',
code: 'ce28664b5308c17f931c0367',
+ link: 'http://localhost/redeem/ce28664b5308c17f931c0367',
createdAt: '2022-03-16T14:22:40.000Z',
holdAvailableAmount: '5.13109484759482747111',
id: 87,
@@ -27,6 +28,7 @@ const propsData = {
{
amount: '6',
code: 'ce28664b5308c17f931c0367',
+ link: 'http://localhost/redeem/ce28664b5308c17f931c0367',
createdAt: '2022-03-16T14:22:40.000Z',
holdAvailableAmount: '5.13109484759482747111',
id: 86,
diff --git a/frontend/src/components/GddSend/TransactionResultLink.vue b/frontend/src/components/GddSend/TransactionResultLink.vue
index ee65b159a..04445acfe 100644
--- a/frontend/src/components/GddSend/TransactionResultLink.vue
+++ b/frontend/src/components/GddSend/TransactionResultLink.vue
@@ -3,13 +3,12 @@
{{ $t('gdd_per_link.created') }}
-
-
+
-
+
-
+
{{ $t('form.close') }}
@@ -28,14 +27,19 @@ export default {
FigureQrCode,
},
props: {
- code: {
+ link: {
type: String,
required: true,
},
},
- computed: {
- link() {
- return `${window.location.origin}/redeem/${this.code}`
+ data() {
+ return {
+ showQrcode: false,
+ }
+ },
+ methods: {
+ showQrCodeButton() {
+ this.showQrcode = !this.showQrcode
},
},
}
diff --git a/frontend/src/components/GddSend/TransactionResultSendError.vue b/frontend/src/components/GddSend/TransactionResultSendError.vue
index 6a3761092..279ee931e 100644
--- a/frontend/src/components/GddSend/TransactionResultSendError.vue
+++ b/frontend/src/components/GddSend/TransactionResultSendError.vue
@@ -22,7 +22,9 @@
{{ errorResult }}
- {{ $t('form.close') }}
+
+ {{ $t('form.close') }}
+
diff --git a/frontend/src/components/GddSend/TransactionResultSendSuccess.vue b/frontend/src/components/GddSend/TransactionResultSendSuccess.vue
index 74bb6963a..bc8c39f3b 100644
--- a/frontend/src/components/GddSend/TransactionResultSendSuccess.vue
+++ b/frontend/src/components/GddSend/TransactionResultSendSuccess.vue
@@ -9,7 +9,7 @@
{{ $t('form.send_transaction_success') }}
- {{ $t('form.close') }}
+ {{ $t('form.close') }}
diff --git a/frontend/src/components/QrCode/FigureQrCode.spec.js b/frontend/src/components/QrCode/FigureQrCode.spec.js
index d19d806d3..715a5d5d5 100644
--- a/frontend/src/components/QrCode/FigureQrCode.spec.js
+++ b/frontend/src/components/QrCode/FigureQrCode.spec.js
@@ -4,7 +4,7 @@ import FigureQrCode from './FigureQrCode'
const localVue = global.localVue
const propsData = {
- text: '',
+ link: '',
}
describe('FigureQrCode', () => {
diff --git a/frontend/src/components/QrCode/FigureQrCode.vue b/frontend/src/components/QrCode/FigureQrCode.vue
index df450a52e..00f1b54b9 100644
--- a/frontend/src/components/QrCode/FigureQrCode.vue
+++ b/frontend/src/components/QrCode/FigureQrCode.vue
@@ -14,14 +14,14 @@ export default {
QRCanvas,
},
props: {
- text: { type: String, required: true },
+ link: { type: String, required: true },
},
data() {
return {
options: {
cellSize: 8,
correctLevel: 'H',
- data: this.text,
+ data: this.link,
},
}
},
diff --git a/frontend/src/components/TransactionLinks/TransactionLink.spec.js b/frontend/src/components/TransactionLinks/TransactionLink.spec.js
index ec2f657c3..ad9e4860e 100644
--- a/frontend/src/components/TransactionLinks/TransactionLink.spec.js
+++ b/frontend/src/components/TransactionLinks/TransactionLink.spec.js
@@ -22,7 +22,7 @@ const mocks = {
const propsData = {
amount: '75',
- code: 'c00000000c000000c0000',
+ link: 'http://localhost/redeem/c00000000c000000c0000',
holdAvailableAmount: '5.13109484759482747111',
id: 12,
memo: 'Katzenauge, Eulenschrei, was verschwunden komm herbei!',
@@ -44,115 +44,140 @@ describe('TransactionLink', () => {
expect(wrapper.find('div.transaction-link').exists()).toBeTruthy()
})
- describe('Copy link to Clipboard', () => {
- const navigatorClipboard = navigator.clipboard
- beforeAll(() => {
- delete navigator.clipboard
- navigator.clipboard = { writeText: navigatorClipboardMock }
- })
- afterAll(() => {
- navigator.clipboard = navigatorClipboard
+ describe('Link validUntil Date is not valid', () => {
+ it('has no copy link button', () => {
+ expect(wrapper.find('.test-copy-link').exists()).toBe(false)
})
- describe('copy with success', () => {
- beforeEach(async () => {
- navigatorClipboardMock.mockResolvedValue()
- await wrapper.find('.test-copy-link').trigger('click')
- })
- it('should call clipboard.writeText', () => {
- expect(navigator.clipboard.writeText).toHaveBeenCalledWith(
- 'http://localhost/redeem/c00000000c000000c0000',
- )
- })
- it('toasts success message', () => {
- expect(toastSuccessSpy).toBeCalledWith('gdd_per_link.link-copied')
- })
+ it('has no Qr-Code Button ', () => {
+ expect(wrapper.find('.test-qr-code').exists()).toBe(false)
+ })
+
+ it('has delete link button ', () => {
+ expect(wrapper.find('.test-delete-link').exists()).toBe(true)
})
})
- describe('qr code modal', () => {
- let spy
-
- beforeEach(() => {
+ describe('Link validUntil Date is valid ', () => {
+ beforeEach(async () => {
+ const now = new Date()
jest.clearAllMocks()
+ await wrapper.setProps({
+ validUntil: `${new Date(now.getFullYear(), now.getMonth(), now.getDate() + 2)}`,
+ })
})
- describe('with success', () => {
+ describe('Copy link to Clipboard', () => {
+ const navigatorClipboard = navigator.clipboard
+ beforeAll(() => {
+ delete navigator.clipboard
+ navigator.clipboard = { writeText: navigatorClipboardMock }
+ })
+ afterAll(() => {
+ navigator.clipboard = navigatorClipboard
+ })
+
+ describe('copy with success', () => {
+ beforeEach(async () => {
+ navigatorClipboardMock.mockResolvedValue()
+ await wrapper.find('.test-copy-link .dropdown-item').trigger('click')
+ })
+
+ it('should call clipboard.writeText', () => {
+ expect(navigator.clipboard.writeText).toHaveBeenCalledWith(
+ 'http://localhost/redeem/c00000000c000000c0000',
+ )
+ })
+ it('toasts success message', () => {
+ expect(toastSuccessSpy).toBeCalledWith('gdd_per_link.link-copied')
+ })
+ })
+ })
+
+ describe('qr code modal', () => {
+ let spy
+
beforeEach(async () => {
- spy = jest.spyOn(wrapper.vm.$bvModal, 'show')
- // spy.mockImplementation(() => Promise.resolve('some value'))
- // mockAPIcall.mockResolvedValue()
- await wrapper.find('.test-qr-code').trigger('click')
+ jest.clearAllMocks()
})
- it('qr-code Modal if show', () => {
- expect(spy).toBeCalled()
+ describe('with success', () => {
+ beforeEach(async () => {
+ spy = jest.spyOn(wrapper.vm.$bvModal, 'show')
+ // spy.mockImplementation(() => Promise.resolve('some value'))
+ // mockAPIcall.mockResolvedValue()
+ await wrapper.find('.test-qr-code .dropdown-item').trigger('click')
+ })
+
+ it('opens the qr-code Modal', () => {
+ expect(spy).toBeCalled()
+ })
})
})
- })
- describe('delete link', () => {
- let spy
+ describe('delete link', () => {
+ let spy
- beforeEach(() => {
- jest.clearAllMocks()
- })
-
- describe('with success', () => {
beforeEach(async () => {
- spy = jest.spyOn(wrapper.vm.$bvModal, 'msgBoxConfirm')
- spy.mockImplementation(() => Promise.resolve('some value'))
- mockAPIcall.mockResolvedValue()
- await wrapper.find('.test-delete-link').trigger('click')
+ jest.clearAllMocks()
})
- it('test Modal if confirm true', () => {
- expect(spy).toBeCalled()
+ describe('with success', () => {
+ beforeEach(async () => {
+ spy = jest.spyOn(wrapper.vm.$bvModal, 'msgBoxConfirm')
+ spy.mockImplementation(() => Promise.resolve('some value'))
+ mockAPIcall.mockResolvedValue()
+ await wrapper.find('.test-delete-link .dropdown-item').trigger('click')
+ })
+
+ it('opens the modal ', () => {
+ expect(spy).toBeCalled()
+ })
+
+ it('calls the API', () => {
+ expect(mockAPIcall).toBeCalledWith(
+ expect.objectContaining({
+ mutation: deleteTransactionLink,
+ variables: {
+ id: 12,
+ },
+ }),
+ )
+ })
+
+ it('toasts a success message', () => {
+ expect(toastSuccessSpy).toBeCalledWith('gdd_per_link.deleted')
+ })
+
+ it('emits reset transaction link list', () => {
+ expect(wrapper.emitted('reset-transaction-link-list')).toBeTruthy()
+ })
})
- it('calls the API', () => {
- expect(mockAPIcall).toBeCalledWith(
- expect.objectContaining({
- mutation: deleteTransactionLink,
- variables: {
- id: 12,
- },
- }),
- )
+ describe('with error', () => {
+ beforeEach(async () => {
+ spy = jest.spyOn(wrapper.vm.$bvModal, 'msgBoxConfirm')
+ spy.mockImplementation(() => Promise.resolve('some value'))
+ mockAPIcall.mockRejectedValue({ message: 'Something went wrong :(' })
+ await wrapper.find('.test-delete-link .dropdown-item').trigger('click')
+ })
+
+ it('toasts an error message', () => {
+ expect(toastErrorSpy).toBeCalledWith('Something went wrong :(')
+ })
})
- it('toasts a success message', () => {
- expect(toastSuccessSpy).toBeCalledWith('gdd_per_link.deleted')
- })
+ describe('cancel delete', () => {
+ beforeEach(async () => {
+ spy = jest.spyOn(wrapper.vm.$bvModal, 'msgBoxConfirm')
+ spy.mockImplementation(() => Promise.resolve(false))
+ mockAPIcall.mockResolvedValue()
+ await wrapper.find('.test-delete-link .dropdown-item').trigger('click')
+ })
- it('emits reset transaction link list', () => {
- expect(wrapper.emitted('reset-transaction-link-list')).toBeTruthy()
- })
- })
-
- describe('with error', () => {
- beforeEach(async () => {
- spy = jest.spyOn(wrapper.vm.$bvModal, 'msgBoxConfirm')
- spy.mockImplementation(() => Promise.resolve('some value'))
- mockAPIcall.mockRejectedValue({ message: 'Something went wrong :(' })
- await wrapper.find('.test-delete-link').trigger('click')
- })
-
- it('toasts an error message', () => {
- expect(toastErrorSpy).toBeCalledWith('Something went wrong :(')
- })
- })
-
- describe('cancel delete', () => {
- beforeEach(async () => {
- spy = jest.spyOn(wrapper.vm.$bvModal, 'msgBoxConfirm')
- spy.mockImplementation(() => Promise.resolve(false))
- mockAPIcall.mockResolvedValue()
- await wrapper.find('.test-delete-link').trigger('click')
- })
-
- it('does not call the API', () => {
- expect(mockAPIcall).not.toBeCalled()
+ it('does not call the API', () => {
+ expect(mockAPIcall).not.toBeCalled()
+ })
})
})
})
diff --git a/frontend/src/components/TransactionLinks/TransactionLink.vue b/frontend/src/components/TransactionLinks/TransactionLink.vue
index 66f9f2f92..5b8e15d5c 100644
--- a/frontend/src/components/TransactionLinks/TransactionLink.vue
+++ b/frontend/src/components/TransactionLinks/TransactionLink.vue
@@ -1,55 +1,54 @@
-
-
+
+
-
+
-
+
-
+
-
-
-
-
+
+
+
+
+
+
+
+
+ {{ $t('gdd_per_link.copy') }}
+
+
+
+ {{ $t('qrCode') }}
+
+
+
+ {{ $t('delete') }}
+
+
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+ {{ $t('qrCode') }}
+
+
+
+ {{ link }}
+
+
@@ -74,7 +73,7 @@ export default {
},
props: {
amount: { type: String, required: true },
- code: { type: String, required: true },
+ link: { type: String, required: true },
holdAvailableAmount: { type: String, required: true },
id: { type: Number, required: true },
memo: { type: String, required: true },
@@ -115,8 +114,8 @@ export default {
decay() {
return `${this.amount - this.holdAvailableAmount}`
},
- link() {
- return `${window.location.origin}/redeem/${this.code}`
+ validLink() {
+ return new Date(this.validUntil) > new Date()
},
},
}
diff --git a/frontend/src/components/TransactionRows/DateRow.vue b/frontend/src/components/TransactionRows/DateRow.vue
index 5f526caaf..5998be134 100644
--- a/frontend/src/components/TransactionRows/DateRow.vue
+++ b/frontend/src/components/TransactionRows/DateRow.vue
@@ -3,7 +3,7 @@
- {{ diffNow ? $t('gdd_per_link.valid_until') : $t('form.date') }}
+ {{ text }}
@@ -27,6 +27,20 @@ export default {
required: false,
default: false,
},
+ validLink: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ },
+ computed: {
+ text() {
+ if (this.diffNow)
+ return this.validLink
+ ? this.$t('gdd_per_link.validUntil')
+ : this.$t('gdd_per_link.expiredOn')
+ return this.$t('form.date')
+ },
},
}
diff --git a/frontend/src/components/Transactions/TransactionLinkSummary.spec.js b/frontend/src/components/Transactions/TransactionLinkSummary.spec.js
index 3e57bceeb..b60cc60f8 100644
--- a/frontend/src/components/Transactions/TransactionLinkSummary.spec.js
+++ b/frontend/src/components/Transactions/TransactionLinkSummary.spec.js
@@ -44,7 +44,7 @@ describe('TransactionLinkSummary', () => {
listTransactionLinks: [
{
amount: '75',
- code: 'ce28664b5308c17f931c0367',
+ link: 'http://localhost/redeem/ce28664b5308c17f931c0367',
createdAt: '2022-03-16T14:22:40.000Z',
holdAvailableAmount: '5.13109484759482747111',
id: 86,
@@ -55,7 +55,7 @@ describe('TransactionLinkSummary', () => {
},
{
amount: '85',
- code: 'ce28664b5308c17f931c0367',
+ link: 'http://localhost/redeem/ce28664b5308c17f931c0367',
createdAt: '2022-03-16T14:22:40.000Z',
holdAvailableAmount: '5.13109484759482747111',
id: 107,
@@ -65,7 +65,7 @@ describe('TransactionLinkSummary', () => {
},
{
amount: '95',
- code: 'ce28664b5308c17f931c0367',
+ link: 'http://localhost/redeem/ce28664b5308c17f931c0367',
createdAt: '2022-03-16T14:22:40.000Z',
holdAvailableAmount: '5.13109484759482747111',
id: 92,
@@ -76,7 +76,7 @@ describe('TransactionLinkSummary', () => {
},
{
amount: '150',
- code: 'ce28664b5308c17f931c0367',
+ link: 'http://localhost/redeem/ce28664b5308c17f931c0367',
createdAt: '2022-03-16T14:22:40.000Z',
holdAvailableAmount: '5.13109484759482747111',
id: 16,
@@ -132,6 +132,27 @@ describe('TransactionLinkSummary', () => {
it('has no component CollapseLinksList', () => {
expect(wrapper.findComponent({ name: 'CollapseLinksList' }).isVisible()).toBe(false)
})
+
+ describe('reopen transaction link details', () => {
+ beforeEach(() => {
+ jest.clearAllMocks()
+ wrapper.find('div.transaction-link-details').trigger('click')
+ })
+
+ it('calls the API to get the list transaction links', () => {
+ expect(apolloQueryMock).toBeCalledWith({
+ query: listTransactionLinks,
+ variables: {
+ currentPage: 1,
+ },
+ fetchPolicy: 'network-only',
+ })
+ })
+
+ it('has four transactionLinks', () => {
+ expect(wrapper.vm.transactionLinks).toHaveLength(4)
+ })
+ })
})
describe('load more transaction links', () => {
@@ -142,7 +163,7 @@ describe('TransactionLinkSummary', () => {
listTransactionLinks: [
{
amount: '76',
- code: 'ce28664b5308c17f931c0367',
+ link: 'http://localhost/redeem/ce28664b5308c17f931c0367',
createdAt: '2022-03-16T14:22:40.000Z',
holdAvailableAmount: '5.13109484759482747111',
id: 87,
@@ -153,7 +174,7 @@ describe('TransactionLinkSummary', () => {
},
{
amount: '86',
- code: 'ce28664b5308c17f931c0367',
+ link: 'http://localhost/redeem/ce28664b5308c17f931c0367',
createdAt: '2022-03-16T14:22:40.000Z',
holdAvailableAmount: '5.13109484759482747111',
id: 108,
@@ -164,7 +185,7 @@ describe('TransactionLinkSummary', () => {
},
{
amount: '96',
- code: 'ce28664b5308c17f931c0367',
+ link: 'http://localhost/redeem/ce28664b5308c17f931c0367',
createdAt: '2022-03-16T14:22:40.000Z',
holdAvailableAmount: '5.13109484759482747111',
id: 93,
@@ -175,7 +196,7 @@ describe('TransactionLinkSummary', () => {
},
{
amount: '150',
- code: 'ce28664b5308c17f931c0367',
+ link: 'http://localhost/redeem/ce28664b5308c17f931c0367',
createdAt: '2022-03-16T14:22:40.000Z',
holdAvailableAmount: '5.13109484759482747111',
id: 17,
diff --git a/frontend/src/components/Transactions/TransactionLinkSummary.vue b/frontend/src/components/Transactions/TransactionLinkSummary.vue
index 84d0f9b84..c24410924 100644
--- a/frontend/src/components/Transactions/TransactionLinkSummary.vue
+++ b/frontend/src/components/Transactions/TransactionLinkSummary.vue
@@ -83,6 +83,7 @@ export default {
if (this.visible) {
this.visible = false
} else {
+ this.transactionLinks = []
this.updateListTransactionLinks()
this.visible = true
}
diff --git a/frontend/src/graphql/mutations.js b/frontend/src/graphql/mutations.js
index 3dbd8888e..672af5f04 100644
--- a/frontend/src/graphql/mutations.js
+++ b/frontend/src/graphql/mutations.js
@@ -75,7 +75,7 @@ export const sendCoins = gql`
export const createTransactionLink = gql`
mutation($amount: Decimal!, $memo: String!) {
createTransactionLink(amount: $amount, memo: $memo) {
- code
+ link
}
}
`
diff --git a/frontend/src/graphql/queries.js b/frontend/src/graphql/queries.js
index 3d5a6a95c..2bd905e5e 100644
--- a/frontend/src/graphql/queries.js
+++ b/frontend/src/graphql/queries.js
@@ -139,7 +139,7 @@ export const listTransactionLinks = gql`
amount
holdAvailableAmount
memo
- code
+ link
createdAt
validUntil
redeemedAt
diff --git a/frontend/src/locales/de.json b/frontend/src/locales/de.json
index 20ce055d4..16111ef4a 100644
--- a/frontend/src/locales/de.json
+++ b/frontend/src/locales/de.json
@@ -102,6 +102,7 @@
"decay-14-day": "Vergänglichkeit für 14 Tage",
"delete-the-link": "Den Link löschen?",
"deleted": "Der Link wurde gelöscht!",
+ "expiredOn": "Abgelaufen am",
"has-account": "Du besitzt bereits ein Gradido Konto?",
"header": "Gradidos versenden per Link",
"isFree": "Gradido ist weltweit kostenfrei.",
@@ -121,7 +122,7 @@
"redeemed-title": "eingelöst",
"to-login": "Log dich ein",
"to-register": "Registriere ein neues Konto.",
- "valid_until": "Gültig bis"
+ "validUntil": "Gültig bis"
},
"gdt": {
"calculation": "Berechnung der Gradido Transform",
@@ -164,6 +165,7 @@
"infoText": "Wenn dir dein Empfehlungsgeber seine Publisher-Id gegeben hat, trage sie hier ein, sonst lass das Feld bitte unverändert!",
"publisherId": "Publisher-Id:"
},
+ "qrCode": "QR Code",
"send_gdd": "GDD versenden",
"send_per_link": "GDD versenden per Link",
"settings": {
diff --git a/frontend/src/locales/en.json b/frontend/src/locales/en.json
index 201c44d93..70a2fabca 100644
--- a/frontend/src/locales/en.json
+++ b/frontend/src/locales/en.json
@@ -102,6 +102,7 @@
"decay-14-day": "Decay for 14 days",
"delete-the-link": "Delete the link?",
"deleted": "The link was deleted!",
+ "expiredOn": "Expired on",
"has-account": "You already have a Gradido account?",
"header": "Send Gradidos via link",
"isFree": "Gradido is free of charge worldwide.",
@@ -121,7 +122,7 @@
"redeemed-title": "redeemed",
"to-login": "Log in",
"to-register": "Register a new account.",
- "valid_until": "Valid until"
+ "validUntil": "Valid until"
},
"gdt": {
"calculation": "Calculation of Gradido Transform",
@@ -164,6 +165,7 @@
"infoText": "If your referrer has given you his publisher id, enter it here, otherwise leave the field unchanged!",
"publisherId": "PublisherID:"
},
+ "qrCode": "QR Code",
"send_gdd": "GDD send",
"send_per_link": "GDD send via link",
"settings": {
diff --git a/frontend/src/pages/Send.spec.js b/frontend/src/pages/Send.spec.js
index 447fdde33..88759c839 100644
--- a/frontend/src/pages/Send.spec.js
+++ b/frontend/src/pages/Send.spec.js
@@ -162,7 +162,11 @@ describe('Send', () => {
describe('transaction form link', () => {
beforeEach(async () => {
apolloMutationMock.mockResolvedValue({
- data: { createTransactionLink: { code: '0123456789' } },
+ data: {
+ createTransactionLink: {
+ link: 'http://localhost/redeem/0123456789',
+ },
+ },
})
const transactionForm = wrapper.findComponent({ name: 'TransactionForm' })
await transactionForm.findAll('input[type="radio"]').at(1).setChecked()
@@ -249,7 +253,7 @@ describe('Send', () => {
describe('close button click', () => {
beforeEach(async () => {
- await wrapper.findAll('button').at(1).trigger('click')
+ await wrapper.findAll('button').at(2).trigger('click')
})
it('Shows the TransactionForm', () => {
diff --git a/frontend/src/pages/Send.vue b/frontend/src/pages/Send.vue
index 613342dba..cd5f8f572 100644
--- a/frontend/src/pages/Send.vue
+++ b/frontend/src/pages/Send.vue
@@ -41,7 +41,7 @@
>
-
+
@@ -87,7 +87,7 @@ export default {
errorResult: '',
currentTransactionStep: TRANSACTION_STEPS.transactionForm,
loading: false,
- code: null,
+ link: null,
}
},
props: {
@@ -144,7 +144,7 @@ export default {
})
.then((result) => {
this.$emit('set-tunneled-email', null)
- this.code = result.data.createTransactionLink.code
+ this.link = result.data.createTransactionLink.link
this.transactionData = { ...EMPTY_TRANSACTION_DATA }
this.currentTransactionStep = TRANSACTION_STEPS.transactionResultLink
this.updateTransactions({})
diff --git a/frontend/yarn.lock b/frontend/yarn.lock
index cc7868ce3..b7648c9c8 100644
--- a/frontend/yarn.lock
+++ b/frontend/yarn.lock
@@ -5276,6 +5276,13 @@ create-hmac@^1.1.0, create-hmac@^1.1.4, create-hmac@^1.1.7:
safe-buffer "^5.0.1"
sha.js "^2.4.8"
+cross-env@^7.0.3:
+ version "7.0.3"
+ resolved "https://registry.yarnpkg.com/cross-env/-/cross-env-7.0.3.tgz#865264b29677dc015ba8418918965dd232fc54cf"
+ integrity sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==
+ dependencies:
+ cross-spawn "^7.0.1"
+
cross-spawn@^5.0.1, cross-spawn@^5.1.0:
version "5.1.0"
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449"
@@ -5296,7 +5303,7 @@ cross-spawn@^6.0.0:
shebang-command "^1.2.0"
which "^1.2.9"
-cross-spawn@^7.0.0, cross-spawn@^7.0.2:
+cross-spawn@^7.0.0, cross-spawn@^7.0.1, cross-spawn@^7.0.2:
version "7.0.3"
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6"
integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==