fix: add donation ga and tests (#38003)
* fix: add donation ga * feat: add ga-saga tests
This commit is contained in:
158
client/package-lock.json
generated
158
client/package-lock.json
generated
@ -4840,8 +4840,7 @@
|
|||||||
"ansi-regex": {
|
"ansi-regex": {
|
||||||
"version": "2.1.1",
|
"version": "2.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
|
||||||
"integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
|
"integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8="
|
||||||
"optional": true
|
|
||||||
},
|
},
|
||||||
"aproba": {
|
"aproba": {
|
||||||
"version": "1.2.0",
|
"version": "1.2.0",
|
||||||
@ -4862,14 +4861,12 @@
|
|||||||
"balanced-match": {
|
"balanced-match": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
|
||||||
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
|
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
|
||||||
"optional": true
|
|
||||||
},
|
},
|
||||||
"brace-expansion": {
|
"brace-expansion": {
|
||||||
"version": "1.1.11",
|
"version": "1.1.11",
|
||||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
|
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
|
||||||
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
|
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"balanced-match": "^1.0.0",
|
"balanced-match": "^1.0.0",
|
||||||
"concat-map": "0.0.1"
|
"concat-map": "0.0.1"
|
||||||
@ -4884,20 +4881,17 @@
|
|||||||
"code-point-at": {
|
"code-point-at": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz",
|
||||||
"integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=",
|
"integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c="
|
||||||
"optional": true
|
|
||||||
},
|
},
|
||||||
"concat-map": {
|
"concat-map": {
|
||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
||||||
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
|
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
|
||||||
"optional": true
|
|
||||||
},
|
},
|
||||||
"console-control-strings": {
|
"console-control-strings": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz",
|
||||||
"integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=",
|
"integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4="
|
||||||
"optional": true
|
|
||||||
},
|
},
|
||||||
"core-util-is": {
|
"core-util-is": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
@ -5014,8 +5008,7 @@
|
|||||||
"inherits": {
|
"inherits": {
|
||||||
"version": "2.0.3",
|
"version": "2.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
|
||||||
"integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=",
|
"integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
|
||||||
"optional": true
|
|
||||||
},
|
},
|
||||||
"ini": {
|
"ini": {
|
||||||
"version": "1.3.5",
|
"version": "1.3.5",
|
||||||
@ -5027,7 +5020,6 @@
|
|||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz",
|
||||||
"integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
|
"integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"number-is-nan": "^1.0.0"
|
"number-is-nan": "^1.0.0"
|
||||||
}
|
}
|
||||||
@ -5042,7 +5034,6 @@
|
|||||||
"version": "3.0.4",
|
"version": "3.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
|
||||||
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
|
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"brace-expansion": "^1.1.7"
|
"brace-expansion": "^1.1.7"
|
||||||
}
|
}
|
||||||
@ -5050,14 +5041,12 @@
|
|||||||
"minimist": {
|
"minimist": {
|
||||||
"version": "0.0.8",
|
"version": "0.0.8",
|
||||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
|
"resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
|
||||||
"integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=",
|
"integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0="
|
||||||
"optional": true
|
|
||||||
},
|
},
|
||||||
"minipass": {
|
"minipass": {
|
||||||
"version": "2.3.5",
|
"version": "2.3.5",
|
||||||
"resolved": "https://registry.npmjs.org/minipass/-/minipass-2.3.5.tgz",
|
"resolved": "https://registry.npmjs.org/minipass/-/minipass-2.3.5.tgz",
|
||||||
"integrity": "sha512-Gi1W4k059gyRbyVUZQ4mEqLm0YIUiGYfvxhF6SIlk3ui1WVxMTGfGdQ2SInh3PDrRTVvPKgULkpJtT4RH10+VA==",
|
"integrity": "sha512-Gi1W4k059gyRbyVUZQ4mEqLm0YIUiGYfvxhF6SIlk3ui1WVxMTGfGdQ2SInh3PDrRTVvPKgULkpJtT4RH10+VA==",
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"safe-buffer": "^5.1.2",
|
"safe-buffer": "^5.1.2",
|
||||||
"yallist": "^3.0.0"
|
"yallist": "^3.0.0"
|
||||||
@ -5076,7 +5065,6 @@
|
|||||||
"version": "0.5.1",
|
"version": "0.5.1",
|
||||||
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
|
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
|
||||||
"integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
|
"integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"minimist": "0.0.8"
|
"minimist": "0.0.8"
|
||||||
}
|
}
|
||||||
@ -5157,8 +5145,7 @@
|
|||||||
"number-is-nan": {
|
"number-is-nan": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz",
|
||||||
"integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=",
|
"integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0="
|
||||||
"optional": true
|
|
||||||
},
|
},
|
||||||
"object-assign": {
|
"object-assign": {
|
||||||
"version": "4.1.1",
|
"version": "4.1.1",
|
||||||
@ -5170,7 +5157,6 @@
|
|||||||
"version": "1.4.0",
|
"version": "1.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
|
||||||
"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
|
"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"wrappy": "1"
|
"wrappy": "1"
|
||||||
}
|
}
|
||||||
@ -5256,8 +5242,7 @@
|
|||||||
"safe-buffer": {
|
"safe-buffer": {
|
||||||
"version": "5.1.2",
|
"version": "5.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
|
||||||
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
|
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
|
||||||
"optional": true
|
|
||||||
},
|
},
|
||||||
"safer-buffer": {
|
"safer-buffer": {
|
||||||
"version": "2.1.2",
|
"version": "2.1.2",
|
||||||
@ -5293,7 +5278,6 @@
|
|||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
|
||||||
"integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
|
"integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"code-point-at": "^1.0.0",
|
"code-point-at": "^1.0.0",
|
||||||
"is-fullwidth-code-point": "^1.0.0",
|
"is-fullwidth-code-point": "^1.0.0",
|
||||||
@ -5313,7 +5297,6 @@
|
|||||||
"version": "3.0.1",
|
"version": "3.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
|
||||||
"integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
|
"integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"ansi-regex": "^2.0.0"
|
"ansi-regex": "^2.0.0"
|
||||||
}
|
}
|
||||||
@ -5357,14 +5340,12 @@
|
|||||||
"wrappy": {
|
"wrappy": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
||||||
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
|
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
|
||||||
"optional": true
|
|
||||||
},
|
},
|
||||||
"yallist": {
|
"yallist": {
|
||||||
"version": "3.0.3",
|
"version": "3.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.3.tgz",
|
||||||
"integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==",
|
"integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A=="
|
||||||
"optional": true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -8757,8 +8738,7 @@
|
|||||||
"ansi-regex": {
|
"ansi-regex": {
|
||||||
"version": "2.1.1",
|
"version": "2.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
|
||||||
"integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
|
"integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8="
|
||||||
"optional": true
|
|
||||||
},
|
},
|
||||||
"aproba": {
|
"aproba": {
|
||||||
"version": "1.2.0",
|
"version": "1.2.0",
|
||||||
@ -8779,14 +8759,12 @@
|
|||||||
"balanced-match": {
|
"balanced-match": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
|
||||||
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
|
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
|
||||||
"optional": true
|
|
||||||
},
|
},
|
||||||
"brace-expansion": {
|
"brace-expansion": {
|
||||||
"version": "1.1.11",
|
"version": "1.1.11",
|
||||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
|
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
|
||||||
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
|
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"balanced-match": "^1.0.0",
|
"balanced-match": "^1.0.0",
|
||||||
"concat-map": "0.0.1"
|
"concat-map": "0.0.1"
|
||||||
@ -8801,20 +8779,17 @@
|
|||||||
"code-point-at": {
|
"code-point-at": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz",
|
||||||
"integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=",
|
"integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c="
|
||||||
"optional": true
|
|
||||||
},
|
},
|
||||||
"concat-map": {
|
"concat-map": {
|
||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
||||||
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
|
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
|
||||||
"optional": true
|
|
||||||
},
|
},
|
||||||
"console-control-strings": {
|
"console-control-strings": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz",
|
||||||
"integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=",
|
"integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4="
|
||||||
"optional": true
|
|
||||||
},
|
},
|
||||||
"core-util-is": {
|
"core-util-is": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
@ -8931,8 +8906,7 @@
|
|||||||
"inherits": {
|
"inherits": {
|
||||||
"version": "2.0.3",
|
"version": "2.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
|
||||||
"integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=",
|
"integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
|
||||||
"optional": true
|
|
||||||
},
|
},
|
||||||
"ini": {
|
"ini": {
|
||||||
"version": "1.3.5",
|
"version": "1.3.5",
|
||||||
@ -8944,7 +8918,6 @@
|
|||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz",
|
||||||
"integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
|
"integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"number-is-nan": "^1.0.0"
|
"number-is-nan": "^1.0.0"
|
||||||
}
|
}
|
||||||
@ -8959,7 +8932,6 @@
|
|||||||
"version": "3.0.4",
|
"version": "3.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
|
||||||
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
|
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"brace-expansion": "^1.1.7"
|
"brace-expansion": "^1.1.7"
|
||||||
}
|
}
|
||||||
@ -8967,14 +8939,12 @@
|
|||||||
"minimist": {
|
"minimist": {
|
||||||
"version": "0.0.8",
|
"version": "0.0.8",
|
||||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
|
"resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
|
||||||
"integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=",
|
"integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0="
|
||||||
"optional": true
|
|
||||||
},
|
},
|
||||||
"minipass": {
|
"minipass": {
|
||||||
"version": "2.3.5",
|
"version": "2.3.5",
|
||||||
"resolved": "https://registry.npmjs.org/minipass/-/minipass-2.3.5.tgz",
|
"resolved": "https://registry.npmjs.org/minipass/-/minipass-2.3.5.tgz",
|
||||||
"integrity": "sha512-Gi1W4k059gyRbyVUZQ4mEqLm0YIUiGYfvxhF6SIlk3ui1WVxMTGfGdQ2SInh3PDrRTVvPKgULkpJtT4RH10+VA==",
|
"integrity": "sha512-Gi1W4k059gyRbyVUZQ4mEqLm0YIUiGYfvxhF6SIlk3ui1WVxMTGfGdQ2SInh3PDrRTVvPKgULkpJtT4RH10+VA==",
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"safe-buffer": "^5.1.2",
|
"safe-buffer": "^5.1.2",
|
||||||
"yallist": "^3.0.0"
|
"yallist": "^3.0.0"
|
||||||
@ -8993,7 +8963,6 @@
|
|||||||
"version": "0.5.1",
|
"version": "0.5.1",
|
||||||
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
|
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
|
||||||
"integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
|
"integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"minimist": "0.0.8"
|
"minimist": "0.0.8"
|
||||||
}
|
}
|
||||||
@ -9080,8 +9049,7 @@
|
|||||||
"number-is-nan": {
|
"number-is-nan": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz",
|
||||||
"integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=",
|
"integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0="
|
||||||
"optional": true
|
|
||||||
},
|
},
|
||||||
"object-assign": {
|
"object-assign": {
|
||||||
"version": "4.1.1",
|
"version": "4.1.1",
|
||||||
@ -9093,7 +9061,6 @@
|
|||||||
"version": "1.4.0",
|
"version": "1.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
|
||||||
"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
|
"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"wrappy": "1"
|
"wrappy": "1"
|
||||||
}
|
}
|
||||||
@ -9179,8 +9146,7 @@
|
|||||||
"safe-buffer": {
|
"safe-buffer": {
|
||||||
"version": "5.1.2",
|
"version": "5.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
|
||||||
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
|
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
|
||||||
"optional": true
|
|
||||||
},
|
},
|
||||||
"safer-buffer": {
|
"safer-buffer": {
|
||||||
"version": "2.1.2",
|
"version": "2.1.2",
|
||||||
@ -9216,7 +9182,6 @@
|
|||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
|
||||||
"integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
|
"integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"code-point-at": "^1.0.0",
|
"code-point-at": "^1.0.0",
|
||||||
"is-fullwidth-code-point": "^1.0.0",
|
"is-fullwidth-code-point": "^1.0.0",
|
||||||
@ -9236,7 +9201,6 @@
|
|||||||
"version": "3.0.1",
|
"version": "3.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
|
||||||
"integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
|
"integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"ansi-regex": "^2.0.0"
|
"ansi-regex": "^2.0.0"
|
||||||
}
|
}
|
||||||
@ -9280,17 +9244,21 @@
|
|||||||
"wrappy": {
|
"wrappy": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
||||||
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
|
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
|
||||||
"optional": true
|
|
||||||
},
|
},
|
||||||
"yallist": {
|
"yallist": {
|
||||||
"version": "3.0.3",
|
"version": "3.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.3.tgz",
|
||||||
"integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==",
|
"integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A=="
|
||||||
"optional": true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"fsm-iterator": {
|
||||||
|
"version": "1.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/fsm-iterator/-/fsm-iterator-1.1.0.tgz",
|
||||||
|
"integrity": "sha1-M33kXeGesgV4jPAuOpVewgZ2Dew=",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"function-bind": {
|
"function-bind": {
|
||||||
"version": "1.1.1",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
|
||||||
@ -12392,8 +12360,7 @@
|
|||||||
"ansi-regex": {
|
"ansi-regex": {
|
||||||
"version": "4.1.0",
|
"version": "4.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
|
||||||
"integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
|
"integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg=="
|
||||||
"optional": true
|
|
||||||
},
|
},
|
||||||
"loose-envify": {
|
"loose-envify": {
|
||||||
"version": "1.4.0",
|
"version": "1.4.0",
|
||||||
@ -12445,7 +12412,6 @@
|
|||||||
"version": "5.2.0",
|
"version": "5.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
|
||||||
"integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
|
"integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"ansi-regex": "^4.1.0"
|
"ansi-regex": "^4.1.0"
|
||||||
}
|
}
|
||||||
@ -15379,6 +15345,12 @@
|
|||||||
"resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz",
|
"resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz",
|
||||||
"integrity": "sha1-QVxEePK8wwEgwizhDtMib30+GOA="
|
"integrity": "sha1-QVxEePK8wwEgwizhDtMib30+GOA="
|
||||||
},
|
},
|
||||||
|
"lodash.ismatch": {
|
||||||
|
"version": "4.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/lodash.ismatch/-/lodash.ismatch-4.4.0.tgz",
|
||||||
|
"integrity": "sha1-dWy1FQyjum8RCFp4hJZF8Yj4Xzc=",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"lodash.isplainobject": {
|
"lodash.isplainobject": {
|
||||||
"version": "4.0.6",
|
"version": "4.0.6",
|
||||||
"resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz",
|
"resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz",
|
||||||
@ -15467,8 +15439,7 @@
|
|||||||
"ansi-regex": {
|
"ansi-regex": {
|
||||||
"version": "4.1.0",
|
"version": "4.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
|
||||||
"integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
|
"integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg=="
|
||||||
"optional": true
|
|
||||||
},
|
},
|
||||||
"string-width": {
|
"string-width": {
|
||||||
"version": "3.1.0",
|
"version": "3.1.0",
|
||||||
@ -15485,7 +15456,6 @@
|
|||||||
"version": "5.2.0",
|
"version": "5.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
|
||||||
"integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
|
"integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"ansi-regex": "^4.1.0"
|
"ansi-regex": "^4.1.0"
|
||||||
}
|
}
|
||||||
@ -19428,6 +19398,20 @@
|
|||||||
"@redux-saga/core": "^1.1.1"
|
"@redux-saga/core": "^1.1.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"redux-saga-test-plan": {
|
||||||
|
"version": "4.0.0-rc.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/redux-saga-test-plan/-/redux-saga-test-plan-4.0.0-rc.3.tgz",
|
||||||
|
"integrity": "sha512-18Ha1AWmP4Xt64cSyJv2j7sH8lwQzdk/LByiyhoNyuqyhzkQzlKlflHr3LqiSCzn3e2AgFxagynto8XGRqsHcg==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"core-js": "^2.4.1",
|
||||||
|
"fsm-iterator": "^1.1.0",
|
||||||
|
"lodash.isequal": "^4.5.0",
|
||||||
|
"lodash.ismatch": "^4.4.0",
|
||||||
|
"object-assign": "^4.1.0",
|
||||||
|
"util-inspect": "^0.1.8"
|
||||||
|
}
|
||||||
|
},
|
||||||
"redux-thunk": {
|
"redux-thunk": {
|
||||||
"version": "2.3.0",
|
"version": "2.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-2.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-2.3.0.tgz",
|
||||||
@ -20073,7 +20057,6 @@
|
|||||||
"version": "0.15.0",
|
"version": "0.15.0",
|
||||||
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.15.0.tgz",
|
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.15.0.tgz",
|
||||||
"integrity": "sha512-xAefmSfN6jqAa7Kuq7LIJY0bwAPG3xlCj0HMEBQk1lxYiDKZscY2xJ5U/61ZTrYbmNQbXa+gc7czPkVo11tnCg==",
|
"integrity": "sha512-xAefmSfN6jqAa7Kuq7LIJY0bwAPG3xlCj0HMEBQk1lxYiDKZscY2xJ5U/61ZTrYbmNQbXa+gc7czPkVo11tnCg==",
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"loose-envify": "^1.1.0",
|
"loose-envify": "^1.1.0",
|
||||||
"object-assign": "^4.1.1"
|
"object-assign": "^4.1.1"
|
||||||
@ -22433,6 +22416,47 @@
|
|||||||
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
|
||||||
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
|
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
|
||||||
},
|
},
|
||||||
|
"util-inspect": {
|
||||||
|
"version": "0.1.8",
|
||||||
|
"resolved": "https://registry.npmjs.org/util-inspect/-/util-inspect-0.1.8.tgz",
|
||||||
|
"integrity": "sha1-KznbzS2SHy2EMJI8r/QPS1zqXbE=",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"array-map": "0.0.0",
|
||||||
|
"array-reduce": "0.0.0",
|
||||||
|
"foreach": "2.0.4",
|
||||||
|
"indexof": "0.0.1",
|
||||||
|
"isarray": "0.0.1",
|
||||||
|
"json3": "3.3.0",
|
||||||
|
"object-keys": "0.5.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"foreach": {
|
||||||
|
"version": "2.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.4.tgz",
|
||||||
|
"integrity": "sha1-zF0NiuHUbMmlVcJoL5EJd4WZNd8=",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"isarray": {
|
||||||
|
"version": "0.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
|
||||||
|
"integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"json3": {
|
||||||
|
"version": "3.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/json3/-/json3-3.3.0.tgz",
|
||||||
|
"integrity": "sha1-Dp5/bF0nC3WJKa9Nb+/chL1m4lk=",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"object-keys": {
|
||||||
|
"version": "0.5.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/object-keys/-/object-keys-0.5.0.tgz",
|
||||||
|
"integrity": "sha1-CeIR8+ADGK/E9ZLjbnzcENmtcpM=",
|
||||||
|
"dev": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"util.promisify": {
|
"util.promisify": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/util.promisify/-/util.promisify-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/util.promisify/-/util.promisify-1.0.0.tgz",
|
||||||
|
@ -104,6 +104,7 @@
|
|||||||
"jest": "^24.9.0",
|
"jest": "^24.9.0",
|
||||||
"jest-dom": "^3.5.0",
|
"jest-dom": "^3.5.0",
|
||||||
"react-test-renderer": "^16.10.2",
|
"react-test-renderer": "^16.10.2",
|
||||||
|
"redux-saga-test-plan": "^4.0.0-rc.3",
|
||||||
"webpack-cli": "^3.3.9"
|
"webpack-cli": "^3.3.9"
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
|
@ -15,7 +15,8 @@ import {
|
|||||||
showCert,
|
showCert,
|
||||||
userFetchStateSelector,
|
userFetchStateSelector,
|
||||||
usernameSelector,
|
usernameSelector,
|
||||||
isDonatingSelector
|
isDonatingSelector,
|
||||||
|
executeGA
|
||||||
} from '../redux';
|
} from '../redux';
|
||||||
import validCertNames from '../../utils/validCertNames';
|
import validCertNames from '../../utils/validCertNames';
|
||||||
import { createFlashMessage } from '../components/Flash/redux';
|
import { createFlashMessage } from '../components/Flash/redux';
|
||||||
@ -37,6 +38,7 @@ const propTypes = {
|
|||||||
certDashedName: PropTypes.string,
|
certDashedName: PropTypes.string,
|
||||||
certName: PropTypes.string,
|
certName: PropTypes.string,
|
||||||
createFlashMessage: PropTypes.func.isRequired,
|
createFlashMessage: PropTypes.func.isRequired,
|
||||||
|
executeGA: PropTypes.func,
|
||||||
fetchState: PropTypes.shape({
|
fetchState: PropTypes.shape({
|
||||||
pending: PropTypes.bool,
|
pending: PropTypes.bool,
|
||||||
complete: PropTypes.bool,
|
complete: PropTypes.bool,
|
||||||
@ -74,19 +76,20 @@ const mapStateToProps = (state, { certName }) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const mapDispatchToProps = dispatch =>
|
const mapDispatchToProps = dispatch =>
|
||||||
bindActionCreators({ createFlashMessage, showCert }, dispatch);
|
bindActionCreators({ createFlashMessage, showCert, executeGA }, dispatch);
|
||||||
|
|
||||||
class ShowCertification extends Component {
|
class ShowCertification extends Component {
|
||||||
constructor(...args) {
|
constructor(...args) {
|
||||||
super(...args);
|
super(...args);
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
closeBtn: false,
|
isDonationSubmitted: false,
|
||||||
donationClosed: false
|
isDonationDisplayed: false,
|
||||||
|
isDonationClosed: false
|
||||||
};
|
};
|
||||||
|
|
||||||
this.hideDonationSection = this.hideDonationSection.bind(this);
|
this.hideDonationSection = this.hideDonationSection.bind(this);
|
||||||
this.showDonationCloseBtn = this.showDonationCloseBtn.bind(this);
|
this.handleProcessing = this.handleProcessing.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
@ -97,12 +100,53 @@ class ShowCertification extends Component {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
hideDonationSection() {
|
shouldComponentUpdate(nextProps) {
|
||||||
this.setState({ donationClosed: true });
|
const {
|
||||||
|
userFetchState: { complete: userComplete },
|
||||||
|
signedInUserName,
|
||||||
|
isDonating,
|
||||||
|
cert: { username = '' },
|
||||||
|
executeGA
|
||||||
|
} = nextProps;
|
||||||
|
const { isDonationDisplayed } = this.state;
|
||||||
|
|
||||||
|
if (
|
||||||
|
!isDonationDisplayed &&
|
||||||
|
userComplete &&
|
||||||
|
signedInUserName === username &&
|
||||||
|
!isDonating
|
||||||
|
) {
|
||||||
|
this.setState({
|
||||||
|
isDonationDisplayed: true
|
||||||
|
});
|
||||||
|
|
||||||
|
executeGA({
|
||||||
|
type: 'event',
|
||||||
|
data: {
|
||||||
|
category: 'Donation',
|
||||||
|
action: 'Displayed Certificate Donation',
|
||||||
|
nonInteraction: true
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
showDonationCloseBtn() {
|
hideDonationSection() {
|
||||||
this.setState({ closeBtn: true });
|
this.setState({ isDonationDisplayed: false, isDonationClosed: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
handleProcessing(duration, amount) {
|
||||||
|
this.props.executeGA({
|
||||||
|
type: 'event',
|
||||||
|
data: {
|
||||||
|
category: 'donation',
|
||||||
|
action: 'certificate stripe form submission',
|
||||||
|
label: duration,
|
||||||
|
value: amount
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.setState({ isDonationSubmitted: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
@ -111,13 +155,14 @@ class ShowCertification extends Component {
|
|||||||
fetchState,
|
fetchState,
|
||||||
validCertName,
|
validCertName,
|
||||||
createFlashMessage,
|
createFlashMessage,
|
||||||
certName,
|
certName
|
||||||
signedInUserName,
|
|
||||||
isDonating,
|
|
||||||
userFetchState
|
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
const { donationClosed, closeBtn } = this.state;
|
const {
|
||||||
|
isDonationSubmitted,
|
||||||
|
isDonationDisplayed,
|
||||||
|
isDonationClosed
|
||||||
|
} = this.state;
|
||||||
|
|
||||||
if (!validCertName) {
|
if (!validCertName) {
|
||||||
createFlashMessage(standardErrorMessage);
|
createFlashMessage(standardErrorMessage);
|
||||||
@ -125,7 +170,6 @@ class ShowCertification extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const { pending, complete, errored } = fetchState;
|
const { pending, complete, errored } = fetchState;
|
||||||
const { complete: userComplete } = userFetchState;
|
|
||||||
|
|
||||||
if (pending) {
|
if (pending) {
|
||||||
return <Loader fullScreen={true} />;
|
return <Loader fullScreen={true} />;
|
||||||
@ -149,8 +193,6 @@ class ShowCertification extends Component {
|
|||||||
completionTime
|
completionTime
|
||||||
} = cert;
|
} = cert;
|
||||||
|
|
||||||
let conditionalDonationSection = '';
|
|
||||||
|
|
||||||
const donationCloseBtn = (
|
const donationCloseBtn = (
|
||||||
<div>
|
<div>
|
||||||
<Button
|
<Button
|
||||||
@ -164,15 +206,9 @@ class ShowCertification extends Component {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
if (
|
let donationSection = (
|
||||||
userComplete &&
|
|
||||||
signedInUserName === username &&
|
|
||||||
!isDonating &&
|
|
||||||
!donationClosed
|
|
||||||
) {
|
|
||||||
conditionalDonationSection = (
|
|
||||||
<Grid className='donation-section'>
|
<Grid className='donation-section'>
|
||||||
{!closeBtn && (
|
{!isDonationSubmitted && (
|
||||||
<Row>
|
<Row>
|
||||||
<Col sm={10} smOffset={1} xs={12}>
|
<Col sm={10} smOffset={1} xs={12}>
|
||||||
<p>
|
<p>
|
||||||
@ -186,21 +222,20 @@ class ShowCertification extends Component {
|
|||||||
</Row>
|
</Row>
|
||||||
)}
|
)}
|
||||||
<MinimalDonateForm
|
<MinimalDonateForm
|
||||||
showCloseBtn={this.showDonationCloseBtn}
|
handleProcessing={this.handleProcessing}
|
||||||
defaultTheme='light'
|
defaultTheme='light'
|
||||||
/>
|
/>
|
||||||
<Row>
|
<Row>
|
||||||
<Col sm={4} smOffset={4} xs={6} xsOffset={3}>
|
<Col sm={4} smOffset={4} xs={6} xsOffset={3}>
|
||||||
{closeBtn ? donationCloseBtn : ''}
|
{isDonationSubmitted && donationCloseBtn}
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
</Grid>
|
</Grid>
|
||||||
);
|
);
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='certificate-outer-wrapper'>
|
<div className='certificate-outer-wrapper'>
|
||||||
{conditionalDonationSection}
|
{isDonationDisplayed && !isDonationClosed ? donationSection : ''}
|
||||||
<Grid className='certificate-wrapper certification-namespace'>
|
<Grid className='certificate-wrapper certification-namespace'>
|
||||||
<Row>
|
<Row>
|
||||||
<header>
|
<header>
|
||||||
|
@ -34,6 +34,7 @@ const numToCommas = num =>
|
|||||||
num.toString().replace(/(\d)(?=(\d{3})+(?!\d))/g, '$1,');
|
num.toString().replace(/(\d)(?=(\d{3})+(?!\d))/g, '$1,');
|
||||||
|
|
||||||
const propTypes = {
|
const propTypes = {
|
||||||
|
handleProcessing: PropTypes.func,
|
||||||
isDonating: PropTypes.bool,
|
isDonating: PropTypes.bool,
|
||||||
isSignedIn: PropTypes.bool,
|
isSignedIn: PropTypes.bool,
|
||||||
navigate: PropTypes.func.isRequired,
|
navigate: PropTypes.func.isRequired,
|
||||||
@ -191,7 +192,7 @@ class DonateForm extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
renderDonationOptions() {
|
renderDonationOptions() {
|
||||||
const { stripe } = this.props;
|
const { stripe, handleProcessing } = this.props;
|
||||||
const { donationAmount, donationDuration, paymentType } = this.state;
|
const { donationAmount, donationDuration, paymentType } = this.state;
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
@ -203,6 +204,7 @@ class DonateForm extends Component {
|
|||||||
donationAmount={donationAmount}
|
donationAmount={donationAmount}
|
||||||
donationDuration={donationDuration}
|
donationDuration={donationDuration}
|
||||||
getDonationButtonLabel={this.getDonationButtonLabel}
|
getDonationButtonLabel={this.getDonationButtonLabel}
|
||||||
|
handleProcessing={handleProcessing}
|
||||||
hideAmountOptionsCB={this.hideAmountOptionsCB}
|
hideAmountOptionsCB={this.hideAmountOptionsCB}
|
||||||
/>
|
/>
|
||||||
</Elements>
|
</Elements>
|
||||||
|
@ -24,6 +24,7 @@ const propTypes = {
|
|||||||
donationDuration: PropTypes.string.isRequired,
|
donationDuration: PropTypes.string.isRequired,
|
||||||
email: PropTypes.string,
|
email: PropTypes.string,
|
||||||
getDonationButtonLabel: PropTypes.func.isRequired,
|
getDonationButtonLabel: PropTypes.func.isRequired,
|
||||||
|
handleProcessing: PropTypes.func,
|
||||||
isSignedIn: PropTypes.bool,
|
isSignedIn: PropTypes.bool,
|
||||||
showCloseBtn: PropTypes.func,
|
showCloseBtn: PropTypes.func,
|
||||||
stripe: PropTypes.shape({
|
stripe: PropTypes.shape({
|
||||||
@ -146,8 +147,11 @@ class DonateFormChildViewForHOC extends Component {
|
|||||||
|
|
||||||
// change the donation modal button label to close
|
// change the donation modal button label to close
|
||||||
// or display the close button for the cert donation section
|
// or display the close button for the cert donation section
|
||||||
if (this.props.showCloseBtn) {
|
if (this.props.handleProcessing) {
|
||||||
this.props.showCloseBtn();
|
this.props.handleProcessing(
|
||||||
|
this.state.donationDuration,
|
||||||
|
Math.round(this.state.donationAmount / 100)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return postChargeStripe({
|
return postChargeStripe({
|
||||||
|
@ -11,11 +11,11 @@ import Heart from '../../assets/icons/Heart';
|
|||||||
import Cup from '../../assets/icons/Cup';
|
import Cup from '../../assets/icons/Cup';
|
||||||
import MinimalDonateForm from './MinimalDonateForm';
|
import MinimalDonateForm from './MinimalDonateForm';
|
||||||
|
|
||||||
import ga from '../../analytics';
|
|
||||||
import {
|
import {
|
||||||
closeDonationModal,
|
closeDonationModal,
|
||||||
isDonationModalOpenSelector,
|
isDonationModalOpenSelector,
|
||||||
isBlockDonationModalSelector
|
isBlockDonationModalSelector,
|
||||||
|
executeGA
|
||||||
} from '../../redux';
|
} from '../../redux';
|
||||||
|
|
||||||
import { challengeMetaSelector } from '../../templates/Challenges/redux';
|
import { challengeMetaSelector } from '../../templates/Challenges/redux';
|
||||||
@ -36,7 +36,8 @@ const mapStateToProps = createSelector(
|
|||||||
const mapDispatchToProps = dispatch =>
|
const mapDispatchToProps = dispatch =>
|
||||||
bindActionCreators(
|
bindActionCreators(
|
||||||
{
|
{
|
||||||
closeDonationModal
|
closeDonationModal,
|
||||||
|
executeGA
|
||||||
},
|
},
|
||||||
dispatch
|
dispatch
|
||||||
);
|
);
|
||||||
@ -45,18 +46,44 @@ const propTypes = {
|
|||||||
activeDonors: PropTypes.number,
|
activeDonors: PropTypes.number,
|
||||||
block: PropTypes.string,
|
block: PropTypes.string,
|
||||||
closeDonationModal: PropTypes.func.isRequired,
|
closeDonationModal: PropTypes.func.isRequired,
|
||||||
|
executeGA: PropTypes.func,
|
||||||
isBlockDonation: PropTypes.bool,
|
isBlockDonation: PropTypes.bool,
|
||||||
show: PropTypes.bool
|
show: PropTypes.bool
|
||||||
};
|
};
|
||||||
|
|
||||||
function DonateModal({ show, block, isBlockDonation, closeDonationModal }) {
|
function DonateModal({
|
||||||
|
show,
|
||||||
|
block,
|
||||||
|
isBlockDonation,
|
||||||
|
closeDonationModal,
|
||||||
|
executeGA
|
||||||
|
}) {
|
||||||
const [closeLabel, setCloseLabel] = React.useState(false);
|
const [closeLabel, setCloseLabel] = React.useState(false);
|
||||||
const showCloseBtn = () => {
|
const handleProcessing = (duration, amount) => {
|
||||||
|
executeGA({
|
||||||
|
type: 'event',
|
||||||
|
data: {
|
||||||
|
category: 'donation',
|
||||||
|
action: 'Modal strip form submission',
|
||||||
|
label: duration,
|
||||||
|
value: amount
|
||||||
|
}
|
||||||
|
});
|
||||||
setCloseLabel(true);
|
setCloseLabel(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
if (show) {
|
if (show) {
|
||||||
ga.modalview('/donation-modal');
|
executeGA({ type: 'modal', data: '/donation-modal' });
|
||||||
|
executeGA({
|
||||||
|
type: 'event',
|
||||||
|
data: {
|
||||||
|
category: 'Donation',
|
||||||
|
action: `Displayed ${
|
||||||
|
isBlockDonation ? 'block' : 'progress'
|
||||||
|
} donation modal`,
|
||||||
|
nonInteraction: true
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const donationText = (
|
const donationText = (
|
||||||
@ -101,7 +128,7 @@ function DonateModal({ show, block, isBlockDonation, closeDonationModal }) {
|
|||||||
<Modal.Body>
|
<Modal.Body>
|
||||||
{isBlockDonation ? blockDonationText : progressDonationText}
|
{isBlockDonation ? blockDonationText : progressDonationText}
|
||||||
<Spacer />
|
<Spacer />
|
||||||
<MinimalDonateForm showCloseBtn={showCloseBtn} />
|
<MinimalDonateForm handleProcessing={handleProcessing} />
|
||||||
<Spacer />
|
<Spacer />
|
||||||
<Row>
|
<Row>
|
||||||
<Col sm={4} smOffset={4} xs={8} xsOffset={2}>
|
<Col sm={4} smOffset={4} xs={8} xsOffset={2}>
|
||||||
|
@ -19,8 +19,8 @@ import './Donation.css';
|
|||||||
|
|
||||||
const propTypes = {
|
const propTypes = {
|
||||||
defaultTheme: PropTypes.string,
|
defaultTheme: PropTypes.string,
|
||||||
|
handleProcessing: PropTypes.func,
|
||||||
isDonating: PropTypes.bool,
|
isDonating: PropTypes.bool,
|
||||||
showCloseBtn: PropTypes.func,
|
|
||||||
stripe: PropTypes.shape({
|
stripe: PropTypes.shape({
|
||||||
createToken: PropTypes.func.isRequired
|
createToken: PropTypes.func.isRequired
|
||||||
})
|
})
|
||||||
@ -79,7 +79,7 @@ class MinimalDonateForm extends Component {
|
|||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { donationAmount, donationDuration, stripe } = this.state;
|
const { donationAmount, donationDuration, stripe } = this.state;
|
||||||
const { showCloseBtn, defaultTheme } = this.props;
|
const { handleProcessing, defaultTheme } = this.props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Row>
|
<Row>
|
||||||
@ -93,7 +93,7 @@ class MinimalDonateForm extends Component {
|
|||||||
getDonationButtonLabel={() =>
|
getDonationButtonLabel={() =>
|
||||||
`Confirm your donation of $5 per month`
|
`Confirm your donation of $5 per month`
|
||||||
}
|
}
|
||||||
showCloseBtn={showCloseBtn}
|
handleProcessing={handleProcessing}
|
||||||
/>
|
/>
|
||||||
</Elements>
|
</Elements>
|
||||||
</StripeProvider>
|
</StripeProvider>
|
||||||
|
@ -5,9 +5,8 @@ import { connect } from 'react-redux';
|
|||||||
import { createSelector } from 'reselect';
|
import { createSelector } from 'reselect';
|
||||||
import { Link } from 'gatsby';
|
import { Link } from 'gatsby';
|
||||||
|
|
||||||
import ga from '../../../analytics';
|
|
||||||
import { makeExpandedBlockSelector, toggleBlock } from '../redux';
|
import { makeExpandedBlockSelector, toggleBlock } from '../redux';
|
||||||
import { completedChallengesSelector } from '../../../redux';
|
import { completedChallengesSelector, executeGA } from '../../../redux';
|
||||||
import Caret from '../../../assets/icons/Caret';
|
import Caret from '../../../assets/icons/Caret';
|
||||||
import { blockNameify } from '../../../../utils/blockNameify';
|
import { blockNameify } from '../../../../utils/blockNameify';
|
||||||
import GreenPass from '../../../assets/icons/GreenPass';
|
import GreenPass from '../../../assets/icons/GreenPass';
|
||||||
@ -29,12 +28,13 @@ const mapStateToProps = (state, ownProps) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const mapDispatchToProps = dispatch =>
|
const mapDispatchToProps = dispatch =>
|
||||||
bindActionCreators({ toggleBlock }, dispatch);
|
bindActionCreators({ toggleBlock, executeGA }, dispatch);
|
||||||
|
|
||||||
const propTypes = {
|
const propTypes = {
|
||||||
blockDashedName: PropTypes.string,
|
blockDashedName: PropTypes.string,
|
||||||
challenges: PropTypes.array,
|
challenges: PropTypes.array,
|
||||||
completedChallenges: PropTypes.arrayOf(PropTypes.string),
|
completedChallenges: PropTypes.arrayOf(PropTypes.string),
|
||||||
|
executeGA: PropTypes.func,
|
||||||
intro: PropTypes.shape({
|
intro: PropTypes.shape({
|
||||||
fields: PropTypes.shape({ slug: PropTypes.string.isRequired }),
|
fields: PropTypes.shape({ slug: PropTypes.string.isRequired }),
|
||||||
frontmatter: PropTypes.shape({
|
frontmatter: PropTypes.shape({
|
||||||
@ -58,19 +58,25 @@ export class Block extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
handleBlockClick() {
|
handleBlockClick() {
|
||||||
const { blockDashedName, toggleBlock } = this.props;
|
const { blockDashedName, toggleBlock, executeGA } = this.props;
|
||||||
ga.event({
|
executeGA({
|
||||||
|
type: 'event',
|
||||||
|
data: {
|
||||||
category: 'Map Block Click',
|
category: 'Map Block Click',
|
||||||
action: blockDashedName
|
action: blockDashedName
|
||||||
|
}
|
||||||
});
|
});
|
||||||
return toggleBlock(blockDashedName);
|
return toggleBlock(blockDashedName);
|
||||||
}
|
}
|
||||||
|
|
||||||
handleChallengeClick(slug) {
|
handleChallengeClick(slug) {
|
||||||
return () => {
|
return () => {
|
||||||
return ga.event({
|
return this.props.executeGA({
|
||||||
|
type: 'event',
|
||||||
|
data: {
|
||||||
category: 'Map Challenge Click',
|
category: 'Map Challenge Click',
|
||||||
action: slug
|
action: slug
|
||||||
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -44,6 +44,7 @@ test('<Block expanded snapshot', () => {
|
|||||||
test('<Block /> should handle toggle clicks correctly', async () => {
|
test('<Block /> should handle toggle clicks correctly', async () => {
|
||||||
const toggleSpy = jest.fn();
|
const toggleSpy = jest.fn();
|
||||||
const toggleMapSpy = jest.fn();
|
const toggleMapSpy = jest.fn();
|
||||||
|
const executeGA = jest.fn();
|
||||||
|
|
||||||
const props = {
|
const props = {
|
||||||
blockDashedName: 'block-a',
|
blockDashedName: 'block-a',
|
||||||
@ -51,6 +52,7 @@ test('<Block /> should handle toggle clicks correctly', async () => {
|
|||||||
completedChallenges: mockCompleted,
|
completedChallenges: mockCompleted,
|
||||||
intro: mockIntroNodes[0],
|
intro: mockIntroNodes[0],
|
||||||
isExpanded: false,
|
isExpanded: false,
|
||||||
|
executeGA: executeGA,
|
||||||
toggleBlock: toggleSpy,
|
toggleBlock: toggleSpy,
|
||||||
toggleMapModal: toggleMapSpy
|
toggleMapModal: toggleMapSpy
|
||||||
};
|
};
|
||||||
|
@ -2,8 +2,7 @@ import React, { Fragment, Component } from 'react';
|
|||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
|
|
||||||
import ga from '../../analytics';
|
import { fetchUser, isSignedInSelector, executeGA } from '../../redux';
|
||||||
import { fetchUser, isSignedInSelector } from '../../redux';
|
|
||||||
import { createSelector } from 'reselect';
|
import { createSelector } from 'reselect';
|
||||||
|
|
||||||
const mapStateToProps = createSelector(
|
const mapStateToProps = createSelector(
|
||||||
@ -13,7 +12,7 @@ const mapStateToProps = createSelector(
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
const mapDispatchToProps = { fetchUser };
|
const mapDispatchToProps = { fetchUser, executeGA };
|
||||||
|
|
||||||
class CertificationLayout extends Component {
|
class CertificationLayout extends Component {
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
@ -21,7 +20,7 @@ class CertificationLayout extends Component {
|
|||||||
if (!isSignedIn) {
|
if (!isSignedIn) {
|
||||||
fetchUser();
|
fetchUser();
|
||||||
}
|
}
|
||||||
ga.pageview(pathname);
|
this.props.executeGA({ type: 'page', data: pathname });
|
||||||
}
|
}
|
||||||
render() {
|
render() {
|
||||||
return <Fragment>{this.props.children}</Fragment>;
|
return <Fragment>{this.props.children}</Fragment>;
|
||||||
@ -31,6 +30,7 @@ class CertificationLayout extends Component {
|
|||||||
CertificationLayout.displayName = 'CertificationLayout';
|
CertificationLayout.displayName = 'CertificationLayout';
|
||||||
CertificationLayout.propTypes = {
|
CertificationLayout.propTypes = {
|
||||||
children: PropTypes.any,
|
children: PropTypes.any,
|
||||||
|
executeGA: PropTypes.func,
|
||||||
fetchUser: PropTypes.func.isRequired,
|
fetchUser: PropTypes.func.isRequired,
|
||||||
isSignedIn: PropTypes.bool,
|
isSignedIn: PropTypes.bool,
|
||||||
pathname: PropTypes.string.isRequired
|
pathname: PropTypes.string.isRequired
|
||||||
|
@ -6,13 +6,13 @@ import { createSelector } from 'reselect';
|
|||||||
import Helmet from 'react-helmet';
|
import Helmet from 'react-helmet';
|
||||||
import fontawesome from '@fortawesome/fontawesome';
|
import fontawesome from '@fortawesome/fontawesome';
|
||||||
|
|
||||||
import ga from '../../analytics';
|
|
||||||
import {
|
import {
|
||||||
fetchUser,
|
fetchUser,
|
||||||
isSignedInSelector,
|
isSignedInSelector,
|
||||||
onlineStatusChange,
|
onlineStatusChange,
|
||||||
isOnlineSelector,
|
isOnlineSelector,
|
||||||
userSelector
|
userSelector,
|
||||||
|
executeGA
|
||||||
} from '../../redux';
|
} from '../../redux';
|
||||||
import { flashMessageSelector, removeFlashMessage } from '../Flash/redux';
|
import { flashMessageSelector, removeFlashMessage } from '../Flash/redux';
|
||||||
|
|
||||||
@ -68,6 +68,7 @@ const metaKeywords = [
|
|||||||
|
|
||||||
const propTypes = {
|
const propTypes = {
|
||||||
children: PropTypes.node.isRequired,
|
children: PropTypes.node.isRequired,
|
||||||
|
executeGA: PropTypes.func,
|
||||||
fetchUser: PropTypes.func.isRequired,
|
fetchUser: PropTypes.func.isRequired,
|
||||||
flashMessage: PropTypes.shape({
|
flashMessage: PropTypes.shape({
|
||||||
id: PropTypes.string,
|
id: PropTypes.string,
|
||||||
@ -101,27 +102,27 @@ const mapStateToProps = createSelector(
|
|||||||
|
|
||||||
const mapDispatchToProps = dispatch =>
|
const mapDispatchToProps = dispatch =>
|
||||||
bindActionCreators(
|
bindActionCreators(
|
||||||
{ fetchUser, removeFlashMessage, onlineStatusChange },
|
{ fetchUser, removeFlashMessage, onlineStatusChange, executeGA },
|
||||||
dispatch
|
dispatch
|
||||||
);
|
);
|
||||||
|
|
||||||
class DefaultLayout extends Component {
|
class DefaultLayout extends Component {
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
const { isSignedIn, fetchUser, pathname } = this.props;
|
const { isSignedIn, fetchUser, pathname, executeGA } = this.props;
|
||||||
if (!isSignedIn) {
|
if (!isSignedIn) {
|
||||||
fetchUser();
|
fetchUser();
|
||||||
}
|
}
|
||||||
ga.pageview(pathname);
|
executeGA({ type: 'page', data: pathname });
|
||||||
|
|
||||||
window.addEventListener('online', this.updateOnlineStatus);
|
window.addEventListener('online', this.updateOnlineStatus);
|
||||||
window.addEventListener('offline', this.updateOnlineStatus);
|
window.addEventListener('offline', this.updateOnlineStatus);
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidUpdate(prevProps) {
|
componentDidUpdate(prevProps) {
|
||||||
const { pathname } = this.props;
|
const { pathname, executeGA } = this.props;
|
||||||
const { pathname: prevPathname } = prevProps;
|
const { pathname: prevPathname } = prevProps;
|
||||||
if (pathname !== prevPathname) {
|
if (pathname !== prevPathname) {
|
||||||
ga.pageview(pathname);
|
executeGA({ type: 'page', data: pathname });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import React, { Component, Fragment } from 'react';
|
import React, { Component, Fragment } from 'react';
|
||||||
import Helmet from 'react-helmet';
|
import Helmet from 'react-helmet';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
|
import { bindActionCreators } from 'redux';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { createSelector } from 'reselect';
|
import { createSelector } from 'reselect';
|
||||||
import { Grid, Row, Col } from '@freecodecamp/react-bootstrap';
|
import { Grid, Row, Col } from '@freecodecamp/react-bootstrap';
|
||||||
@ -9,10 +10,11 @@ import { stripePublicKey } from '../../config/env.json';
|
|||||||
import { Spacer, Loader } from '../components/helpers';
|
import { Spacer, Loader } from '../components/helpers';
|
||||||
import DonateForm from '../components/Donation/DonateForm';
|
import DonateForm from '../components/Donation/DonateForm';
|
||||||
import DonateText from '../components/Donation/DonateText';
|
import DonateText from '../components/Donation/DonateText';
|
||||||
import { signInLoadingSelector, userSelector } from '../redux';
|
import { signInLoadingSelector, userSelector, executeGA } from '../redux';
|
||||||
import { stripeScriptLoader } from '../utils/scriptLoaders';
|
import { stripeScriptLoader } from '../utils/scriptLoaders';
|
||||||
|
|
||||||
const propTypes = {
|
const propTypes = {
|
||||||
|
executeGA: PropTypes.func,
|
||||||
isDonating: PropTypes.bool,
|
isDonating: PropTypes.bool,
|
||||||
showLoading: PropTypes.bool.isRequired
|
showLoading: PropTypes.bool.isRequired
|
||||||
};
|
};
|
||||||
@ -26,6 +28,14 @@ const mapStateToProps = createSelector(
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const mapDispatchToProps = dispatch =>
|
||||||
|
bindActionCreators(
|
||||||
|
{
|
||||||
|
executeGA
|
||||||
|
},
|
||||||
|
dispatch
|
||||||
|
);
|
||||||
|
|
||||||
export class DonatePage extends Component {
|
export class DonatePage extends Component {
|
||||||
constructor(...props) {
|
constructor(...props) {
|
||||||
super(...props);
|
super(...props);
|
||||||
@ -33,11 +43,19 @@ export class DonatePage extends Component {
|
|||||||
stripe: null,
|
stripe: null,
|
||||||
enableSettings: false
|
enableSettings: false
|
||||||
};
|
};
|
||||||
|
this.handleProcessing = this.handleProcessing.bind(this);
|
||||||
this.handleStripeLoad = this.handleStripeLoad.bind(this);
|
this.handleStripeLoad = this.handleStripeLoad.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
|
this.props.executeGA({
|
||||||
|
type: 'event',
|
||||||
|
data: {
|
||||||
|
category: 'Donation',
|
||||||
|
action: `Displayed donate page`,
|
||||||
|
nonInteraction: true
|
||||||
|
}
|
||||||
|
});
|
||||||
if (window.Stripe) {
|
if (window.Stripe) {
|
||||||
this.handleStripeLoad();
|
this.handleStripeLoad();
|
||||||
} else if (document.querySelector('#stripe-js')) {
|
} else if (document.querySelector('#stripe-js')) {
|
||||||
@ -56,6 +74,18 @@ export class DonatePage extends Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
handleProcessing(duration, amount) {
|
||||||
|
this.props.executeGA({
|
||||||
|
type: 'event',
|
||||||
|
data: {
|
||||||
|
category: 'donation',
|
||||||
|
action: 'donate page stripe form submission',
|
||||||
|
label: duration,
|
||||||
|
value: amount
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
handleStripeLoad() {
|
handleStripeLoad() {
|
||||||
// Create Stripe instance once Stripe.js loads
|
// Create Stripe instance once Stripe.js loads
|
||||||
console.info('stripe has loaded');
|
console.info('stripe has loaded');
|
||||||
@ -98,6 +128,7 @@ export class DonatePage extends Component {
|
|||||||
<Col md={6}>
|
<Col md={6}>
|
||||||
<DonateForm
|
<DonateForm
|
||||||
enableDonationSettingsPage={this.enableDonationSettingsPage}
|
enableDonationSettingsPage={this.enableDonationSettingsPage}
|
||||||
|
handleProcessing={this.handleProcessing}
|
||||||
stripe={stripe}
|
stripe={stripe}
|
||||||
/>
|
/>
|
||||||
</Col>
|
</Col>
|
||||||
@ -117,4 +148,7 @@ export class DonatePage extends Component {
|
|||||||
DonatePage.displayName = 'DonatePage';
|
DonatePage.displayName = 'DonatePage';
|
||||||
DonatePage.propTypes = propTypes;
|
DonatePage.propTypes = propTypes;
|
||||||
|
|
||||||
export default connect(mapStateToProps)(DonatePage);
|
export default connect(
|
||||||
|
mapStateToProps,
|
||||||
|
mapDispatchToProps
|
||||||
|
)(DonatePage);
|
||||||
|
12
client/src/redux/ga-saga.js
Normal file
12
client/src/redux/ga-saga.js
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
import { takeEvery, call, all } from 'redux-saga/effects';
|
||||||
|
import ga from '../analytics';
|
||||||
|
|
||||||
|
const GaTypes = { event: ga.event, page: ga.pageview, modal: ga.modalview };
|
||||||
|
|
||||||
|
function* callGaType({ payload: { type, data } }) {
|
||||||
|
yield call(GaTypes[type], data);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function* createGaSaga(types) {
|
||||||
|
yield all([takeEvery(types.executeGA, callGaType)]);
|
||||||
|
}
|
28
client/src/redux/ga-saga.test.js
Normal file
28
client/src/redux/ga-saga.test.js
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
import { types } from '.';
|
||||||
|
import { createGaSaga } from './ga-saga';
|
||||||
|
import ga from '../analytics';
|
||||||
|
import { expectSaga } from 'redux-saga-test-plan';
|
||||||
|
|
||||||
|
describe('ga-saga', () => {
|
||||||
|
it('calls GA after executeGA action', () => {
|
||||||
|
const GaTypes = { event: ga.event, page: ga.pageview, modal: ga.modalview };
|
||||||
|
const mockEventPayload = {
|
||||||
|
type: 'event',
|
||||||
|
data: {
|
||||||
|
category: 'donation',
|
||||||
|
action: 'year end gift paypal button click'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
expectSaga(createGaSaga, types)
|
||||||
|
// Assert that the `call` with expected pramater will eventually happen.
|
||||||
|
.call(GaTypes.event, mockEventPayload.data)
|
||||||
|
|
||||||
|
// Dispatch any actions that the saga will `take`.
|
||||||
|
.dispatch({ type: types.executeGA, payload: mockEventPayload })
|
||||||
|
|
||||||
|
// Start the test.
|
||||||
|
.run()
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
@ -11,6 +11,7 @@ import { createReportUserSaga } from './report-user-saga';
|
|||||||
import { createShowCertSaga } from './show-cert-saga';
|
import { createShowCertSaga } from './show-cert-saga';
|
||||||
import { createNightModeSaga } from './night-mode-saga';
|
import { createNightModeSaga } from './night-mode-saga';
|
||||||
import { createDonationSaga } from './donation-saga';
|
import { createDonationSaga } from './donation-saga';
|
||||||
|
import { createGaSaga } from './ga-saga';
|
||||||
|
|
||||||
import hardGoToEpic from './hard-go-to-epic';
|
import hardGoToEpic from './hard-go-to-epic';
|
||||||
import failedUpdatesEpic from './failed-updates-epic';
|
import failedUpdatesEpic from './failed-updates-epic';
|
||||||
@ -65,6 +66,7 @@ export const types = createTypes(
|
|||||||
'onlineStatusChange',
|
'onlineStatusChange',
|
||||||
'resetUserData',
|
'resetUserData',
|
||||||
'tryToShowDonationModal',
|
'tryToShowDonationModal',
|
||||||
|
'executeGA',
|
||||||
'submitComplete',
|
'submitComplete',
|
||||||
'updateComplete',
|
'updateComplete',
|
||||||
'updateCurrentChallengeId',
|
'updateCurrentChallengeId',
|
||||||
@ -84,6 +86,7 @@ export const sagas = [
|
|||||||
...createAcceptTermsSaga(types),
|
...createAcceptTermsSaga(types),
|
||||||
...createAppMountSaga(types),
|
...createAppMountSaga(types),
|
||||||
...createDonationSaga(types),
|
...createDonationSaga(types),
|
||||||
|
...createGaSaga(types),
|
||||||
...createFetchUserSaga(types),
|
...createFetchUserSaga(types),
|
||||||
...createShowCertSaga(types),
|
...createShowCertSaga(types),
|
||||||
...createReportUserSaga(types),
|
...createReportUserSaga(types),
|
||||||
@ -95,6 +98,9 @@ export const appMount = createAction(types.appMount);
|
|||||||
export const tryToShowDonationModal = createAction(
|
export const tryToShowDonationModal = createAction(
|
||||||
types.tryToShowDonationModal
|
types.tryToShowDonationModal
|
||||||
);
|
);
|
||||||
|
|
||||||
|
export const executeGA = createAction(types.executeGA);
|
||||||
|
|
||||||
export const allowBlockDonationRequests = createAction(
|
export const allowBlockDonationRequests = createAction(
|
||||||
types.allowBlockDonationRequests
|
types.allowBlockDonationRequests
|
||||||
);
|
);
|
||||||
|
@ -6,10 +6,8 @@ import { createSelector } from 'reselect';
|
|||||||
import { Button, Modal } from '@freecodecamp/react-bootstrap';
|
import { Button, Modal } from '@freecodecamp/react-bootstrap';
|
||||||
import { useStaticQuery, graphql } from 'gatsby';
|
import { useStaticQuery, graphql } from 'gatsby';
|
||||||
|
|
||||||
import ga from '../../../analytics';
|
|
||||||
import Login from '../../../components/Header/components/Login';
|
import Login from '../../../components/Header/components/Login';
|
||||||
import CompletionModalBody from './CompletionModalBody';
|
import CompletionModalBody from './CompletionModalBody';
|
||||||
|
|
||||||
import { dasherize } from '../../../../../utils/slugs';
|
import { dasherize } from '../../../../../utils/slugs';
|
||||||
|
|
||||||
import './completion-modal.css';
|
import './completion-modal.css';
|
||||||
@ -25,7 +23,7 @@ import {
|
|||||||
lastBlockChalSubmitted
|
lastBlockChalSubmitted
|
||||||
} from '../redux';
|
} from '../redux';
|
||||||
|
|
||||||
import { isSignedInSelector } from '../../../redux';
|
import { isSignedInSelector, executeGA } from '../../../redux';
|
||||||
|
|
||||||
const mapStateToProps = createSelector(
|
const mapStateToProps = createSelector(
|
||||||
challengeFilesSelector,
|
challengeFilesSelector,
|
||||||
@ -60,7 +58,8 @@ const mapDispatchToProps = function(dispatch) {
|
|||||||
},
|
},
|
||||||
lastBlockChalSubmitted: () => {
|
lastBlockChalSubmitted: () => {
|
||||||
dispatch(lastBlockChalSubmitted());
|
dispatch(lastBlockChalSubmitted());
|
||||||
}
|
},
|
||||||
|
executeGA
|
||||||
};
|
};
|
||||||
return () => dispatchers;
|
return () => dispatchers;
|
||||||
};
|
};
|
||||||
@ -70,6 +69,7 @@ const propTypes = {
|
|||||||
close: PropTypes.func.isRequired,
|
close: PropTypes.func.isRequired,
|
||||||
completedChallengesIds: PropTypes.array,
|
completedChallengesIds: PropTypes.array,
|
||||||
currentBlockIds: PropTypes.array,
|
currentBlockIds: PropTypes.array,
|
||||||
|
executeGA: PropTypes.func,
|
||||||
files: PropTypes.object.isRequired,
|
files: PropTypes.object.isRequired,
|
||||||
id: PropTypes.string,
|
id: PropTypes.string,
|
||||||
isOpen: PropTypes.bool,
|
isOpen: PropTypes.bool,
|
||||||
@ -190,7 +190,7 @@ export class CompletionModalInner extends Component {
|
|||||||
const { completedPercent } = this.state;
|
const { completedPercent } = this.state;
|
||||||
|
|
||||||
if (isOpen) {
|
if (isOpen) {
|
||||||
ga.modalview('/completion-modal');
|
executeGA({ type: 'modal', data: '/completion-modal' });
|
||||||
}
|
}
|
||||||
const dashedName = dasherize(title);
|
const dashedName = dasherize(title);
|
||||||
return (
|
return (
|
||||||
|
@ -4,21 +4,22 @@ import { bindActionCreators } from 'redux';
|
|||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { Button, Modal } from '@freecodecamp/react-bootstrap';
|
import { Button, Modal } from '@freecodecamp/react-bootstrap';
|
||||||
|
|
||||||
import ga from '../../../analytics';
|
|
||||||
import { createQuestion, closeModal, isHelpModalOpenSelector } from '../redux';
|
import { createQuestion, closeModal, isHelpModalOpenSelector } from '../redux';
|
||||||
|
import { executeGA } from '../../../redux';
|
||||||
|
|
||||||
import './help-modal.css';
|
import './help-modal.css';
|
||||||
|
|
||||||
const mapStateToProps = state => ({ isOpen: isHelpModalOpenSelector(state) });
|
const mapStateToProps = state => ({ isOpen: isHelpModalOpenSelector(state) });
|
||||||
const mapDispatchToProps = dispatch =>
|
const mapDispatchToProps = dispatch =>
|
||||||
bindActionCreators(
|
bindActionCreators(
|
||||||
{ createQuestion, closeHelpModal: () => closeModal('help') },
|
{ createQuestion, executeGA, closeHelpModal: () => closeModal('help') },
|
||||||
dispatch
|
dispatch
|
||||||
);
|
);
|
||||||
|
|
||||||
const propTypes = {
|
const propTypes = {
|
||||||
closeHelpModal: PropTypes.func.isRequired,
|
closeHelpModal: PropTypes.func.isRequired,
|
||||||
createQuestion: PropTypes.func.isRequired,
|
createQuestion: PropTypes.func.isRequired,
|
||||||
|
executeGA: PropTypes.func,
|
||||||
isOpen: PropTypes.bool
|
isOpen: PropTypes.bool
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -27,9 +28,9 @@ const RSA =
|
|||||||
|
|
||||||
export class HelpModal extends Component {
|
export class HelpModal extends Component {
|
||||||
render() {
|
render() {
|
||||||
const { isOpen, closeHelpModal, createQuestion } = this.props;
|
const { isOpen, closeHelpModal, createQuestion, executeGA } = this.props;
|
||||||
if (isOpen) {
|
if (isOpen) {
|
||||||
ga.modalview('/help-modal');
|
executeGA({ type: 'modal', data: '/help-modal' });
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<Modal dialogClassName='help-modal' onHide={closeHelpModal} show={isOpen}>
|
<Modal dialogClassName='help-modal' onHide={closeHelpModal} show={isOpen}>
|
||||||
|
@ -5,13 +5,14 @@ import { connect } from 'react-redux';
|
|||||||
import { createSelector } from 'reselect';
|
import { createSelector } from 'reselect';
|
||||||
import { Button, Modal } from '@freecodecamp/react-bootstrap';
|
import { Button, Modal } from '@freecodecamp/react-bootstrap';
|
||||||
|
|
||||||
import ga from '../../../analytics';
|
|
||||||
import { isResetModalOpenSelector, closeModal, resetChallenge } from '../redux';
|
import { isResetModalOpenSelector, closeModal, resetChallenge } from '../redux';
|
||||||
|
import { executeGA } from '../../../redux';
|
||||||
|
|
||||||
import './reset-modal.css';
|
import './reset-modal.css';
|
||||||
|
|
||||||
const propTypes = {
|
const propTypes = {
|
||||||
close: PropTypes.func.isRequired,
|
close: PropTypes.func.isRequired,
|
||||||
|
executeGA: PropTypes.func,
|
||||||
isOpen: PropTypes.bool.isRequired,
|
isOpen: PropTypes.bool.isRequired,
|
||||||
reset: PropTypes.func.isRequired
|
reset: PropTypes.func.isRequired
|
||||||
};
|
};
|
||||||
@ -25,7 +26,11 @@ const mapStateToProps = createSelector(
|
|||||||
|
|
||||||
const mapDispatchToProps = dispatch =>
|
const mapDispatchToProps = dispatch =>
|
||||||
bindActionCreators(
|
bindActionCreators(
|
||||||
{ close: () => closeModal('reset'), reset: () => resetChallenge() },
|
{
|
||||||
|
close: () => closeModal('reset'),
|
||||||
|
executeGA,
|
||||||
|
reset: () => resetChallenge()
|
||||||
|
},
|
||||||
dispatch
|
dispatch
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -35,7 +40,7 @@ function withActions(...fns) {
|
|||||||
|
|
||||||
function ResetModal({ reset, close, isOpen }) {
|
function ResetModal({ reset, close, isOpen }) {
|
||||||
if (isOpen) {
|
if (isOpen) {
|
||||||
ga.modalview('/reset-modal');
|
executeGA({ type: 'modal', data: '/reset-modal' });
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
|
@ -4,26 +4,30 @@ import { bindActionCreators } from 'redux';
|
|||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { Modal } from '@freecodecamp/react-bootstrap';
|
import { Modal } from '@freecodecamp/react-bootstrap';
|
||||||
|
|
||||||
import ga from '../../../analytics';
|
|
||||||
import { closeModal, isVideoModalOpenSelector } from '../redux';
|
import { closeModal, isVideoModalOpenSelector } from '../redux';
|
||||||
|
import { executeGA } from '../../../redux';
|
||||||
|
|
||||||
import './video-modal.css';
|
import './video-modal.css';
|
||||||
|
|
||||||
const mapStateToProps = state => ({ isOpen: isVideoModalOpenSelector(state) });
|
const mapStateToProps = state => ({ isOpen: isVideoModalOpenSelector(state) });
|
||||||
const mapDispatchToProps = dispatch =>
|
const mapDispatchToProps = dispatch =>
|
||||||
bindActionCreators({ closeVideoModal: () => closeModal('video') }, dispatch);
|
bindActionCreators(
|
||||||
|
{ closeVideoModal: () => closeModal('video'), executeGA },
|
||||||
|
dispatch
|
||||||
|
);
|
||||||
|
|
||||||
const propTypes = {
|
const propTypes = {
|
||||||
closeVideoModal: PropTypes.func.isRequired,
|
closeVideoModal: PropTypes.func.isRequired,
|
||||||
|
executeGA: PropTypes.func,
|
||||||
isOpen: PropTypes.bool,
|
isOpen: PropTypes.bool,
|
||||||
videoUrl: PropTypes.string
|
videoUrl: PropTypes.string
|
||||||
};
|
};
|
||||||
|
|
||||||
export class VideoModal extends Component {
|
export class VideoModal extends Component {
|
||||||
render() {
|
render() {
|
||||||
const { isOpen, closeVideoModal, videoUrl } = this.props;
|
const { isOpen, closeVideoModal, videoUrl, executeGA } = this.props;
|
||||||
if (isOpen) {
|
if (isOpen) {
|
||||||
ga.modalview('/video-modal');
|
executeGA({ type: 'modal', data: '/completion-modal' });
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
|
Reference in New Issue
Block a user