Compare commits

...

61 Commits

Author SHA1 Message Date
SabreCat
b87527bcea 4.237.0 2022-07-29 16:26:29 -05:00
SabreCat
0adfc9f756 chore(subproject): update habitica-images 2022-07-29 16:26:15 -05:00
SabreCat
9a2b49b4bf Revert "chore(content): add August 2022 Backgrounds and Enchanted Armoire Items (#14149)"
This reverts commit 2748455f16.
2022-07-29 16:25:14 -05:00
SabreCat
750a02053c feat(content): August 2022 subscriber items
Code by @CuriousMagpie
2022-07-29 16:24:32 -05:00
Natalie L
2748455f16 chore(content): add August 2022 Backgrounds and Enchanted Armoire Items (#14149)
* chore(submodule): add August 2022 Mystery Items

* chore(content): August 2022 Backgrounds and Enchanted Armoire Items

* chore(submodule): August 2022 Backgrounds and Enchanted Armoire images

* fix(typo): space

* fix(whitespace): spaces

Co-authored-by: Sabe Jones <sabrecat@gmail.com>
2022-07-29 16:21:20 -05:00
SabreCat
cc0e807609 4.236.3 2022-07-21 15:36:17 -05:00
SabreCat
bbc5a54a3e Merge branch 'develop' into release 2022-07-21 15:36:13 -05:00
Sabe Jones
8e717de039 Server setting to disallow chat from new accounts (#13952)
* feat(chat): server setting to disallow chat from new accounts

* fix(tests): many adjustments to handle chat minimum age

* fix(tests): address issues outside of chat posting

* chore(analytics): add incident logging

* fix(config): allow instant chat for dev purposes

* fix(test): finely age one more user

* fix(test): member not leader

Co-authored-by: SabreCat <sabe@habitica.com>
2022-07-21 15:32:28 -05:00
Natalie L
ce18e614be Gifting modal design - amazonModal.vue update (#14131)
* update selectUserModal.vue

* more updates to selectUserModal.vue, typo fix in subscriber.json

* remove exact sizing for selectUserModal.vue

* update to size for selectUserModal.vue

* added sendGiftModal.vue file

* updates to selectUser & sendGift modals

* making the modals go & position cursor

* working working working

* added a return to method

* avatar display & placeholder profile.name and username

* subscription-options added

* added menu row & started on gem options

* Added selectPage function, have not tested.

* updated habitica-images

* state changes

* bringing in gem counter

* arranging elements

* state changes, gem input boxes

* styling sendGiftModal.vue

* more sendGiftModal.vue styling and new close.svg icon

* more styling!

* and more styling of send own gems part of page

* images update

* more styling of own gems & some attempts to adjust :class on the menu

* styling styling styling

* replace +/- svg, styling

* styling, mostly

* new SVGs

* stylin'

* reverting svg changes

* no more stylin'

* finally got the +/- icons to show up...but they're the wrong color

* solved svg icon color problem! :)

* habitica-images

* working on sendGift part of button

* trying to make it do math, failing

* more attempts at math

* +/- buttons work on gem pages & cost calculation on buyGems

* trying to get hover colors working on +/- svgs

* formatted dollar amount as currency

* css/html for subscription-options & payments-buttons simplified

* swag at payments-buttons parameter (not tested)

* send gems from own balance works!

* working on starting page

* increment gem amount limited to maxGems and not < 0

* uncommented onHide()

* got bg color on sub options to work! yay!

* payment buttons!

* making g1g1 look good

* position modal on page properly & code clean-up

* Changes as requested!

* small color update

* fixed ternary function

* chore(html): indentation and comments

* fix(fn): correct catch for under-0

* chore(json): whitespace

* update gem styling; add linebreak to notifications.vue bc linter

* updating subscriptionOptions

* snackbar css fix

* reverting commit e16c12f

* removing merge conflict markers

* just a little comment

* fixed some navigation, clear input field on selectPage, cleaned up code; another try at subscriptionOption.vue

* merge upstream/develop

* update selectPage() to disable Gems menu items when on 'ownGems' or 'buyGems' states

* working on subscriptionOptions.vue logic

* fix(script): changed props & added updateSubscriptionData()

* fix(script): forgot to call updateSubscriptionData()

* fix(scripts): corrected :userReceivingGift on sendGiftModal.vue

* fix(scripts): correct props userReceivingGift to an Object

* fix(scripts): corrected v-if & revised props

* fix(style/html/whitespace): updated css for close.svg and added missing </div>

* style(radio-buttons): updated focus states and added hover states

* style(radio-buttons): refined focus and hover states

* fix(function): changed buyGemsLink to buyGems; still working on menu

* style(radio buttons): ensured consistent display of radio buttons through-out site; still struggling with hover states

* style(radio buttons): updated focus/active/hover to match design & removed unnecessary code

* fix: set default subscription option to 1 month

* fix(function): add default amounts to gem states when modal selected from user profile

* fix(build): use develop package json

* fix: SCSS commenting & abstracted setGemsDefault()

* fix(packages): revert to develop

* fix: remove unnecessary console.log statement

* fix(payments): storePaymentStatusAndReload() modified

Co-authored-by: SabreCat <sabe@habitica.com>
2022-07-21 14:06:50 -05:00
dependabot[bot]
58c27c2610 build(deps): bump apidoc from 0.51.1 to 0.52.0 (#14126)
Bumps [apidoc](https://github.com/apidoc/apidoc) from 0.51.1 to 0.52.0.
- [Release notes](https://github.com/apidoc/apidoc/releases)
- [Changelog](https://github.com/apidoc/apidoc/blob/master/CHANGELOG.md)
- [Commits](https://github.com/apidoc/apidoc/compare/0.51.1...0.52.0)

---
updated-dependencies:
- dependency-name: apidoc
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-07-18 17:03:16 -04:00
dependabot[bot]
220dd51f85 build(deps): bump core-js from 3.23.4 to 3.23.5 in /website/client (#14127)
Bumps [core-js](https://github.com/zloirock/core-js) from 3.23.4 to 3.23.5.
- [Release notes](https://github.com/zloirock/core-js/releases)
- [Changelog](https://github.com/zloirock/core-js/blob/master/CHANGELOG.md)
- [Commits](https://github.com/zloirock/core-js/compare/v3.23.4...v3.23.5)

---
updated-dependencies:
- dependency-name: core-js
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-07-18 17:02:59 -04:00
Vi Mio
3b1407f529 feat: prevent user from purchasing a quest if prerequisites are not met (#14073)
* feat: prevent user from purchasing a quest if prerequisites are not met

* test: fail to buy quest if not all prerequisites are met

* test: modify to check all quest prerequisites
2022-07-14 15:24:52 -05:00
SabreCat
be7b3076eb 4.236.2 2022-07-13 14:52:10 -05:00
negue
2b4ffdf27f filter out bank challenge if is not userSupport 2022-07-13 14:52:05 -05:00
negue
e0dc608fd8 Transaction Logs - Backend Changes 2022-07-13 14:51:56 -05:00
negue
0b4059aab0 Transaction Logs - Backend Changes (#14113)
* Transaction Logs - Backend Changes

* filter out bank challenge if is not userSupport
2022-07-13 14:18:59 -05:00
Natalie L
3aa7b8b447 Gifting modal design (#14124)
* update selectUserModal.vue

* more updates to selectUserModal.vue, typo fix in subscriber.json

* remove exact sizing for selectUserModal.vue

* update to size for selectUserModal.vue

* added sendGiftModal.vue file

* updates to selectUser & sendGift modals

* making the modals go & position cursor

* working working working

* added a return to method

* avatar display & placeholder profile.name and username

* subscription-options added

* added menu row & started on gem options

* Added selectPage function, have not tested.

* updated habitica-images

* state changes

* bringing in gem counter

* arranging elements

* state changes, gem input boxes

* styling sendGiftModal.vue

* more sendGiftModal.vue styling and new close.svg icon

* more styling!

* and more styling of send own gems part of page

* images update

* more styling of own gems & some attempts to adjust :class on the menu

* styling styling styling

* replace +/- svg, styling

* styling, mostly

* new SVGs

* stylin'

* reverting svg changes

* no more stylin'

* finally got the +/- icons to show up...but they're the wrong color

* solved svg icon color problem! :)

* habitica-images

* working on sendGift part of button

* trying to make it do math, failing

* more attempts at math

* +/- buttons work on gem pages & cost calculation on buyGems

* trying to get hover colors working on +/- svgs

* formatted dollar amount as currency

* css/html for subscription-options & payments-buttons simplified

* swag at payments-buttons parameter (not tested)

* send gems from own balance works!

* working on starting page

* increment gem amount limited to maxGems and not < 0

* uncommented onHide()

* got bg color on sub options to work! yay!

* payment buttons!

* making g1g1 look good

* position modal on page properly & code clean-up

* Changes as requested!

* small color update

* fixed ternary function

* chore(html): indentation and comments

* fix(fn): correct catch for under-0

* chore(json): whitespace

* update gem styling; add linebreak to notifications.vue bc linter

* updating subscriptionOptions

* snackbar css fix

* reverting commit e16c12f

* removing merge conflict markers

* just a little comment

* fixed some navigation, clear input field on selectPage, cleaned up code; another try at subscriptionOption.vue

* merge upstream/develop

* update selectPage() to disable Gems menu items when on 'ownGems' or 'buyGems' states

* working on subscriptionOptions.vue logic

* fix(script): changed props & added updateSubscriptionData()

* fix(script): forgot to call updateSubscriptionData()

* fix(scripts): corrected :userReceivingGift on sendGiftModal.vue

* fix(scripts): correct props userReceivingGift to an Object

* fix(scripts): corrected v-if & revised props

* fix(style/html/whitespace): updated css for close.svg and added missing </div>

* style(radio-buttons): updated focus states and added hover states

* style(radio-buttons): refined focus and hover states

* fix(function): changed buyGemsLink to buyGems; still working on menu

* style(radio buttons): ensured consistent display of radio buttons through-out site; still struggling with hover states

* style(radio buttons): updated focus/active/hover to match design & removed unnecessary code

* fix: set default subscription option to 1 month

* fix(function): add default amounts to gem states when modal selected from user profile

* fix(build): use develop package json

* fix: SCSS commenting & abstracted setGemsDefault()

* fix(packages): revert to develop

* fix: remove unnecessary console.log statement

Co-authored-by: SabreCat <sabe@habitica.com>
2022-07-13 14:17:28 -05:00
dependabot[bot]
94b9bb1036 build(deps): bump image-size from 1.0.1 to 1.0.2 (#14123)
Bumps [image-size](https://github.com/image-size/image-size) from 1.0.1 to 1.0.2.
- [Release notes](https://github.com/image-size/image-size/releases)
- [Commits](https://github.com/image-size/image-size/compare/v1.0.1...v1.0.2)

---
updated-dependencies:
- dependency-name: image-size
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-07-13 12:11:38 -04:00
dependabot[bot]
a2f169ab76 build(deps): bump core-js from 3.23.3 to 3.23.4 in /website/client (#14114)
Bumps [core-js](https://github.com/zloirock/core-js) from 3.23.3 to 3.23.4.
- [Release notes](https://github.com/zloirock/core-js/releases)
- [Changelog](https://github.com/zloirock/core-js/blob/master/CHANGELOG.md)
- [Commits](https://github.com/zloirock/core-js/compare/v3.23.3...v3.23.4)

---
updated-dependencies:
- dependency-name: core-js
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-07-13 12:10:45 -04:00
SabreCat
6d345740ff Merge branch 'release' into develop 2022-07-12 10:06:07 -05:00
SabreCat
294cc63fef 4.236.1 2022-07-12 10:05:09 -05:00
SabreCat
9a879d566e fix(content): correct availability range for Seafoam 2022-07-12 10:05:02 -05:00
Scott Coffrin
8ecb0f45b5 Modal responsive improvements (#14087)
* stack profile actions on smaller screens

* stack avatar and stats for even smaller screens

* remove unnecessary classes to keep profile nav on the same line

* adjust media query width

* refactor stats removing unnecessary classes and simplifying with less elements and relying more on flexbox

* adjust breakpoints for modal vs pofile page

* more margin for avatar

* handle allocation on middle size more gracefully

Co-authored-by: scoffrin <scoffrin@indeed.com>
2022-07-08 15:49:22 -05:00
darkarchana
b04df06a37 Fix no response when password changed (#14054)
* Fix no response when password changed

* Update website/client/src/components/settings/site.vue

update the spacing in website/client/src/components/settings/site.vue

Co-authored-by: Panu Valtanen <p4nu@users.noreply.github.com>

* Update website/client/src/components/settings/site.vue

change to single quote

* Fix success change password response using internationalization

* fix(i18n): remove translations other than US English
Partial revert of #1a198677bd

Co-authored-by: Panu Valtanen <p4nu@users.noreply.github.com>
Co-authored-by: SabreCat <sabe@habitica.com>
2022-07-08 15:42:18 -05:00
bbqben
706cffa71d 🐛 Update fetch language call to not retrieve from cache (#14099)
Co-authored-by: Ben Tran <bentran@Bens-Intel-MacBook-Pro.local>
2022-07-06 15:32:07 -05:00
dependabot[bot]
00b8f4fef5 build(deps): bump moment from 2.29.3 to 2.29.4 (#14111)
Bumps [moment](https://github.com/moment/moment) from 2.29.3 to 2.29.4.
- [Release notes](https://github.com/moment/moment/releases)
- [Changelog](https://github.com/moment/moment/blob/develop/CHANGELOG.md)
- [Commits](https://github.com/moment/moment/compare/2.29.3...2.29.4)

---
updated-dependencies:
- dependency-name: moment
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-07-06 15:28:28 -05:00
dependabot[bot]
5ea675b8a5 build(deps): bump async from 2.6.3 to 2.6.4 in /website/client (#14109)
Bumps [async](https://github.com/caolan/async) from 2.6.3 to 2.6.4.
- [Release notes](https://github.com/caolan/async/releases)
- [Changelog](https://github.com/caolan/async/blob/v2.6.4/CHANGELOG.md)
- [Commits](https://github.com/caolan/async/compare/v2.6.3...v2.6.4)

---
updated-dependencies:
- dependency-name: async
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-07-06 15:28:12 -05:00
dependabot[bot]
78f0c71387 build(deps): bump moment from 2.29.3 to 2.29.4 in /website/client (#14112)
Bumps [moment](https://github.com/moment/moment) from 2.29.3 to 2.29.4.
- [Release notes](https://github.com/moment/moment/releases)
- [Changelog](https://github.com/moment/moment/blob/develop/CHANGELOG.md)
- [Commits](https://github.com/moment/moment/compare/2.29.3...2.29.4)

---
updated-dependencies:
- dependency-name: moment
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-07-06 15:28:01 -05:00
SabreCat
e674ef4035 Merge branch 'release' into develop 2022-07-06 14:34:24 -05:00
SabreCat
1655e2e03a 4.236.0 2022-07-06 14:32:58 -05:00
Natalie L
0d444a9d6a chore(content): prebuild July Enchanted Armoire and Backgrounds (#14108) 2022-07-06 14:30:40 -05:00
dependabot[bot]
de331f5e76 build(deps-dev): bump @babel/plugin-proposal-optional-chaining (#14105)
Bumps [@babel/plugin-proposal-optional-chaining](https://github.com/babel/babel/tree/HEAD/packages/babel-plugin-proposal-optional-chaining) from 7.17.12 to 7.18.6.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.18.6/packages/babel-plugin-proposal-optional-chaining)

---
updated-dependencies:
- dependency-name: "@babel/plugin-proposal-optional-chaining"
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-07-05 16:06:03 -04:00
dependabot[bot]
c48043ec90 build(deps): bump @vue/cli-plugin-eslint in /website/client (#14106)
Bumps [@vue/cli-plugin-eslint](https://github.com/vuejs/vue-cli/tree/HEAD/packages/@vue/cli-plugin-eslint) from 4.5.18 to 4.5.19.
- [Release notes](https://github.com/vuejs/vue-cli/releases)
- [Changelog](https://github.com/vuejs/vue-cli/blob/dev/CHANGELOG.md)
- [Commits](https://github.com/vuejs/vue-cli/commits/v4.5.19/packages/@vue/cli-plugin-eslint)

---
updated-dependencies:
- dependency-name: "@vue/cli-plugin-eslint"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-07-05 16:03:41 -04:00
dependabot[bot]
ac4d148170 build(deps): bump winston from 3.8.0 to 3.8.1 (#14103)
Bumps [winston](https://github.com/winstonjs/winston) from 3.8.0 to 3.8.1.
- [Release notes](https://github.com/winstonjs/winston/releases)
- [Changelog](https://github.com/winstonjs/winston/blob/master/CHANGELOG.md)
- [Commits](https://github.com/winstonjs/winston/compare/v3.8.0...v3.8.1)

---
updated-dependencies:
- dependency-name: winston
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-07-05 16:01:03 -04:00
dependabot[bot]
ca49e995be build(deps): bump @babel/preset-env from 7.18.2 to 7.18.6 (#14098)
Bumps [@babel/preset-env](https://github.com/babel/babel/tree/HEAD/packages/babel-preset-env) from 7.18.2 to 7.18.6.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.18.6/packages/babel-preset-env)

---
updated-dependencies:
- dependency-name: "@babel/preset-env"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-07-05 15:43:56 -04:00
SabreCat
d47a867149 Merge branch 'release' into develop 2022-07-05 14:34:30 -05:00
SabreCat
f4d9c6271b 4.235.1 2022-07-05 14:34:17 -05:00
Natalie L
0e458683fd chore(content): add splashySkins for Summer Gala event (#14107)
* chore(content): add splashySkins for Summer Gala event

* fix(content): use date string, not Boolean, for range start

Co-authored-by: SabreCat <sabe@habitica.com>
2022-07-05 14:33:50 -05:00
Alys
76ab93f501 add deilann to moderators in Tavern and Community Guidelines
Note that his picture is still needed in the Community Guidelines
and when that's done, the "(not yet pictured)" text should be removed
2022-07-02 14:04:09 +10:00
Alys
5d4600f5c7 add banned words - TRIGGER / CONTENT WARNING: assault, slurs, swearwords, etc 2022-07-01 20:55:34 +10:00
dependabot[bot]
13c4a726c7 build(deps): bump @babel/core from 7.18.5 to 7.18.6 (#14097)
Bumps [@babel/core](https://github.com/babel/babel/tree/HEAD/packages/babel-core) from 7.18.5 to 7.18.6.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.18.6/packages/babel-core)

---
updated-dependencies:
- dependency-name: "@babel/core"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-06-30 13:45:15 -04:00
dependabot[bot]
43122805fb build(deps): bump @babel/register from 7.17.7 to 7.18.6 (#14096)
Bumps [@babel/register](https://github.com/babel/babel/tree/HEAD/packages/babel-register) from 7.17.7 to 7.18.6.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.18.6/packages/babel-register)

---
updated-dependencies:
- dependency-name: "@babel/register"
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-06-30 13:44:55 -04:00
dependabot[bot]
1262d8f36e build(deps): bump core-js from 3.23.1 to 3.23.3 in /website/client (#14094)
Bumps [core-js](https://github.com/zloirock/core-js) from 3.23.1 to 3.23.3.
- [Release notes](https://github.com/zloirock/core-js/releases)
- [Changelog](https://github.com/zloirock/core-js/blob/master/CHANGELOG.md)
- [Commits](https://github.com/zloirock/core-js/compare/v3.23.1...v3.23.3)

---
updated-dependencies:
- dependency-name: core-js
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-06-30 13:42:41 -04:00
dependabot[bot]
2b1635ff62 build(deps): bump winston from 3.7.2 to 3.8.0 (#14093)
Bumps [winston](https://github.com/winstonjs/winston) from 3.7.2 to 3.8.0.
- [Release notes](https://github.com/winstonjs/winston/releases)
- [Changelog](https://github.com/winstonjs/winston/blob/master/CHANGELOG.md)
- [Commits](https://github.com/winstonjs/winston/compare/v3.7.2...v3.8.0)

---
updated-dependencies:
- dependency-name: winston
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-06-30 13:42:19 -04:00
dependabot[bot]
e1664d2f87 build(deps): bump amplitude-js from 8.18.4 to 8.18.5 in /website/client (#14089)
Bumps [amplitude-js](https://github.com/amplitude/amplitude-javascript) from 8.18.4 to 8.18.5.
- [Release notes](https://github.com/amplitude/amplitude-javascript/releases)
- [Changelog](https://github.com/amplitude/Amplitude-JavaScript/blob/main/CHANGELOG.md)
- [Commits](https://github.com/amplitude/amplitude-javascript/compare/v8.18.4...v8.18.5)

---
updated-dependencies:
- dependency-name: amplitude-js
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-06-30 13:39:42 -04:00
SabreCat
6975b6061b Merge branch 'release' into develop 2022-06-29 14:04:39 -05:00
SabreCat
695a5cc24d 4.235.0 2022-06-29 14:04:28 -05:00
Natalie L
dcced2debb chore(content): July 2022 Mystery Items (#14095)
* merge upstream/release into release

* chore(content): Added July 2022 Mystery Items
2022-06-29 14:02:46 -05:00
SabreCat
88af9c13a8 4.234.2 2022-06-27 16:35:20 -05:00
SabreCat
d5926ef7f1 fix(auth): null string validation error on unique email conflict 2022-06-27 16:35:13 -05:00
SabreCat
e9222e4f7c fix(strings): revise text because left-handedness confuses people 2022-06-27 16:11:23 -05:00
SabreCat
cd0278c6b3 fix(strings): cherry-pick update by @CuriousMagpie 2022-06-24 15:44:48 -05:00
Natalie L
9680c94087 fix(strings): removed extra word in headSpecialSummer2022WarriorNotes (#14088)
* fix(string): questVice1Notes html changed to a mobile-device friendly format

* fix(strings): updated limited.json with "dateEnd" & "monthYYYY" months & put in chronological order

* fix(string): remove extra word from headSpecialSummer2022WarriorNotes

* fix(string): corrected armorSpecialSummer2022MageNotes
2022-06-24 15:43:38 -05:00
Weblate
76de241675 Added translation using Weblate (Cebuano)
Added translation using Weblate (Cebuano)

Added translation using Weblate (Cebuano)

Added translation using Weblate (Cebuano)

Merge branch 'origin/develop' into Weblate.

Translated using Weblate (Portuguese)

Currently translated at 83.9% (115 of 137 strings)

Translated using Weblate (Portuguese)

Currently translated at 83.9% (115 of 137 strings)

Translated using Weblate (Portuguese)

Currently translated at 83.9% (115 of 137 strings)

Translated using Weblate (Greek)

Currently translated at 75.0% (6 of 8 strings)

Translated using Weblate (German)

Currently translated at 100.0% (2607 of 2607 strings)

Translated using Weblate (German)

Currently translated at 100.0% (2607 of 2607 strings)

Translated using Weblate (Filipino)

Currently translated at 43.8% (1139 of 2597 strings)

Translated using Weblate (Filipino)

Currently translated at 43.7% (1137 of 2597 strings)

Translated using Weblate (Italian)

Currently translated at 100.0% (2607 of 2607 strings)

Translated using Weblate (Italian)

Currently translated at 100.0% (704 of 704 strings)

Translated using Weblate (Dutch)

Currently translated at 90.6% (2363 of 2607 strings)

Translated using Weblate (Dutch)

Currently translated at 100.0% (704 of 704 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 98.5% (135 of 137 strings)

Translated using Weblate (French)

Currently translated at 100.0% (755 of 755 strings)

Translated using Weblate (German)

Currently translated at 100.0% (755 of 755 strings)

Co-authored-by: Benoit Hetru <me+hbtc@gahanka.net>
Co-authored-by: Céu <marcel.ufscar@gmail.com>
Co-authored-by: Hexe des Windes (she/her) <krausanna1@gmail.com>
Co-authored-by: Lucifer <selmanreyhan@gmail.com>
Co-authored-by: Mara S. (Dolichotis) <marascherzer@gmail.com>
Co-authored-by: Martim Pinto Paiva <pintopaivam@gmail.com>
Co-authored-by: Nathan Monteiro <nathanspeeds1@outlook.com>
Co-authored-by: Panagiotis Zachos <panzaxos@gmail.com>
Co-authored-by: Sandra Marcial <sandramarcial80@gmail.com>
Co-authored-by: SunshineRain <suusykraft@gmail.com>
Co-authored-by: Vince Vilan <vincemorel.vilan.889@my.csun.edu>
Co-authored-by: Weblate <noreply@weblate.org>
Translate-URL: https://translate.habitica.com/projects/habitica/achievements/pt/
Translate-URL: https://translate.habitica.com/projects/habitica/achievements/pt_BR/
Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/it/
Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/nl/
Translate-URL: https://translate.habitica.com/projects/habitica/gear/de/
Translate-URL: https://translate.habitica.com/projects/habitica/gear/fil/
Translate-URL: https://translate.habitica.com/projects/habitica/gear/it/
Translate-URL: https://translate.habitica.com/projects/habitica/gear/nl/
Translate-URL: https://translate.habitica.com/projects/habitica/overview/el/
Translate-URL: https://translate.habitica.com/projects/habitica/questscontent/de/
Translate-URL: https://translate.habitica.com/projects/habitica/questscontent/fr/
Translation: Habitica/Achievements
Translation: Habitica/Backgrounds
Translation: Habitica/Gear
Translation: Habitica/Overview
Translation: Habitica/Questscontent
2022-06-22 21:18:17 +02:00
SabreCat
3ba6b4a209 feat(language): initialize Cebuano for translation 2022-06-22 14:04:51 -05:00
SabreCat
b101d43e62 Merge branch 'release' into develop 2022-06-21 13:50:35 -05:00
dependabot[bot]
c0e8d80966 build(deps): bump @vue/cli-plugin-eslint in /website/client (#14084)
Bumps [@vue/cli-plugin-eslint](https://github.com/vuejs/vue-cli/tree/HEAD/packages/@vue/cli-plugin-eslint) from 4.5.17 to 4.5.18.
- [Release notes](https://github.com/vuejs/vue-cli/releases)
- [Changelog](https://github.com/vuejs/vue-cli/blob/dev/CHANGELOG.md)
- [Commits](https://github.com/vuejs/vue-cli/commits/v4.5.18/packages/@vue/cli-plugin-eslint)

---
updated-dependencies:
- dependency-name: "@vue/cli-plugin-eslint"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-06-21 13:02:34 -04:00
dependabot[bot]
afacd497d7 build(deps): bump core-js from 3.22.8 to 3.23.1 in /website/client (#14082)
Bumps [core-js](https://github.com/zloirock/core-js) from 3.22.8 to 3.23.1.
- [Release notes](https://github.com/zloirock/core-js/releases)
- [Changelog](https://github.com/zloirock/core-js/blob/master/CHANGELOG.md)
- [Commits](https://github.com/zloirock/core-js/compare/v3.22.8...v3.23.1)

---
updated-dependencies:
- dependency-name: core-js
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-06-21 13:02:07 -04:00
SabreCat
dc744de4a9 Merge branch 'release' into develop 2022-06-21 09:33:35 -05:00
dependabot[bot]
f44bebb573 build(deps): bump jpeg-js from 0.4.3 to 0.4.4 (#14071)
Bumps [jpeg-js](https://github.com/eugeneware/jpeg-js) from 0.4.3 to 0.4.4.
- [Release notes](https://github.com/eugeneware/jpeg-js/releases)
- [Commits](https://github.com/eugeneware/jpeg-js/compare/v0.4.3...v0.4.4)

---
updated-dependencies:
- dependency-name: jpeg-js
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-06-17 13:26:08 -04:00
dependabot[bot]
8ccf701aec build(deps): bump @storybook/addons in /website/client (#14066)
Bumps [@storybook/addons](https://github.com/storybookjs/storybook/tree/HEAD/lib/addons) from 6.5.8 to 6.5.9.
- [Release notes](https://github.com/storybookjs/storybook/releases)
- [Changelog](https://github.com/storybookjs/storybook/blob/v6.5.9/CHANGELOG.md)
- [Commits](https://github.com/storybookjs/storybook/commits/v6.5.9/lib/addons)

---
updated-dependencies:
- dependency-name: "@storybook/addons"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-06-16 16:18:59 -04:00
78 changed files with 2642 additions and 1361 deletions

View File

@@ -1,4 +1,5 @@
{
"ACCOUNT_MIN_CHAT_AGE": "0",
"ADMIN_EMAIL": "you@example.com",
"AMAZON_PAYMENTS_CLIENT_ID": "CLIENT_ID",
"AMAZON_PAYMENTS_MODE": "sandbox",

2168
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,19 +1,19 @@
{
"name": "habitica",
"description": "A habit tracker app which treats your goals like a Role Playing Game.",
"version": "4.234.1",
"version": "4.237.0",
"main": "./website/server/index.js",
"dependencies": {
"@babel/core": "^7.18.5",
"@babel/preset-env": "^7.18.2",
"@babel/register": "^7.17.7",
"@babel/core": "^7.18.6",
"@babel/preset-env": "^7.18.6",
"@babel/register": "^7.18.6",
"@google-cloud/trace-agent": "^5.1.6",
"@parse/node-apn": "^5.1.3",
"@slack/webhook": "^6.1.0",
"accepts": "^1.3.8",
"amazon-payments": "^0.2.9",
"amplitude": "^6.0.0",
"apidoc": "^0.51.1",
"apidoc": "^0.52.0",
"apple-auth": "^1.0.7",
"bcrypt": "^5.0.1",
"body-parser": "^1.20.0",
@@ -39,7 +39,7 @@
"gulp.spritesmith": "^6.13.0",
"habitica-markdown": "^3.0.0",
"helmet": "^4.6.0",
"image-size": "^1.0.1",
"image-size": "^1.0.2",
"in-app-purchase": "^1.11.3",
"js2xmlparser": "^4.0.2",
"jsonwebtoken": "^8.5.1",
@@ -47,7 +47,7 @@
"lodash": "^4.17.21",
"merge-stream": "^2.0.0",
"method-override": "^3.0.0",
"moment": "^2.29.3",
"moment": "^2.29.4",
"moment-recur": "^1.0.7",
"mongoose": "^5.13.7",
"morgan": "^1.10.0",
@@ -74,7 +74,7 @@
"uuid": "^8.3.2",
"validator": "^13.7.0",
"vinyl-buffer": "^1.0.1",
"winston": "^3.7.2",
"winston": "^3.8.1",
"winston-loggly-bulk": "^3.2.1",
"xml2js": "^0.4.23"
},

View File

@@ -15,6 +15,10 @@ describe('DELETE /groups/:groupId/chat/:chatId', () => {
type: 'guild',
privacy: 'public',
},
leaderDetails: {
'auth.timestamps.created': new Date('2022-01-01'),
balance: 10,
},
});
groupWithChat = group;

View File

@@ -117,7 +117,9 @@ describe('POST /chat/:chatId/flag', () => {
});
it('Flags a chat when the author\'s account was deleted', async () => {
const deletedUser = await generateUser();
const deletedUser = await generateUser({
'auth.timestamps.created': new Date('2022-01-01'),
});
const { message } = await deletedUser.post(`/groups/${group._id}/chat`, { message: TEST_MESSAGE });
await deletedUser.del('/user', {
password: 'password',

View File

@@ -18,11 +18,16 @@ describe('POST /chat/:chatId/like', () => {
privacy: 'public',
},
members: 1,
leaderDetails: {
'auth.timestamps.created': new Date('2022-01-01'),
balance: 10,
},
});
user = groupLeader;
groupWithChat = group;
anotherUser = members[0]; // eslint-disable-line prefer-destructuring
await anotherUser.update({ 'auth.timestamps.created': new Date('2022-01-01') });
});
it('Returns an error when chat message is not found', async () => {

View File

@@ -38,10 +38,15 @@ describe('POST /chat', () => {
members: 2,
});
user = groupLeader;
await user.update({ 'contributor.level': SPAM_MIN_EXEMPT_CONTRIB_LEVEL }); // prevent tests accidentally throwing messageGroupChatSpam
await user.update({
'contributor.level': SPAM_MIN_EXEMPT_CONTRIB_LEVEL,
'auth.timestamps.created': new Date('2022-01-01'),
}); // prevent tests accidentally throwing messageGroupChatSpam
groupWithChat = group;
member = members[0]; // eslint-disable-line prefer-destructuring
additionalMember = members[1]; // eslint-disable-line prefer-destructuring
await member.update({ 'auth.timestamps.created': new Date('2022-01-01') });
await additionalMember.update({ 'auth.timestamps.created': new Date('2022-01-01') });
});
it('Returns an error when no message is provided', async () => {
@@ -104,7 +109,10 @@ describe('POST /chat', () => {
});
const privateGuildMemberWithChatsRevoked = members[0];
await privateGuildMemberWithChatsRevoked.update({ 'flags.chatRevoked': true });
await privateGuildMemberWithChatsRevoked.update({
'flags.chatRevoked': true,
'auth.timestamps.created': new Date('2022-01-01'),
});
const message = await privateGuildMemberWithChatsRevoked.post(`/groups/${group._id}/chat`, { message: testMessage });
@@ -122,7 +130,10 @@ describe('POST /chat', () => {
});
const privatePartyMemberWithChatsRevoked = members[0];
await privatePartyMemberWithChatsRevoked.update({ 'flags.chatRevoked': true });
await privatePartyMemberWithChatsRevoked.update({
'flags.chatRevoked': true,
'auth.timestamps.created': new Date('2022-01-01'),
});
const message = await privatePartyMemberWithChatsRevoked.post(`/groups/${group._id}/chat`, { message: testMessage });
@@ -183,7 +194,10 @@ describe('POST /chat', () => {
});
const userWithChatShadowMuted = members[0];
await userWithChatShadowMuted.update({ 'flags.chatShadowMuted': true });
await userWithChatShadowMuted.update({
'flags.chatShadowMuted': true,
'auth.timestamps.created': new Date('2022-01-01'),
});
const message = await userWithChatShadowMuted.post(`/groups/${group._id}/chat`, { message: testMessage });
@@ -202,7 +216,10 @@ describe('POST /chat', () => {
});
const userWithChatShadowMuted = members[0];
await userWithChatShadowMuted.update({ 'flags.chatShadowMuted': true });
await userWithChatShadowMuted.update({
'flags.chatShadowMuted': true,
'auth.timestamps.created': new Date('2022-01-01'),
});
const message = await userWithChatShadowMuted.post(`/groups/${group._id}/chat`, { message: testMessage });
@@ -312,6 +329,7 @@ describe('POST /chat', () => {
},
members: 1,
});
await members[0].update({ 'auth.timestamps.created': new Date('2022-01-01') });
const message = await members[0].post(`/groups/${group._id}/chat`, { message: testBannedWordMessage });
@@ -330,6 +348,7 @@ describe('POST /chat', () => {
// Update the bannedWordsAllowed property for the group
group.update({ bannedWordsAllowed: true });
await members[0].update({ 'auth.timestamps.created': new Date('2022-01-01') });
const message = await members[0].post(`/groups/${group._id}/chat`, { message: testBannedWordMessage });
@@ -345,6 +364,7 @@ describe('POST /chat', () => {
},
members: 1,
});
await members[0].update({ 'auth.timestamps.created': new Date('2022-01-01') });
const message = await members[0].post(`/groups/${group._id}/chat`, { message: testBannedWordMessage });
@@ -411,6 +431,7 @@ describe('POST /chat', () => {
},
members: 1,
});
await members[0].update({ 'auth.timestamps.created': new Date('2022-01-01') });
const message = await members[0].post(`/groups/${group._id}/chat`, { message: testSlurMessage });
@@ -430,6 +451,16 @@ describe('POST /chat', () => {
});
});
it('errors when user account is too young', async () => {
const brandNewUser = await generateUser();
await expect(brandNewUser.post('/groups/habitrpg/chat', { message: 'hi im new' }))
.to.eventually.be.rejected.and.eql({
code: 400,
error: 'BadRequest',
message: t('chatTemporarilyUnavailable'),
});
});
it('creates a chat', async () => {
const newMessage = await user.post(`/groups/${groupWithChat._id}/chat`, { message: testMessage });
const groupMessages = await user.get(`/groups/${groupWithChat._id}/chat`);
@@ -492,6 +523,7 @@ describe('POST /chat', () => {
'items.currentMount': mount,
'items.currentPet': pet,
'preferences.style': style,
'auth.timestamps.created': new Date('2022-01-01'),
});
await userWithStyle.sync();
@@ -517,6 +549,7 @@ describe('POST /chat', () => {
};
const backer = await generateUser({
backer: backerInfo,
'auth.timestamps.created': new Date('2022-01-01'),
});
const message = await backer.post(`/groups/${groupWithChat._id}/chat`, { message: testMessage });
@@ -587,6 +620,9 @@ describe('POST /chat', () => {
privacy: 'private',
},
members: 1,
leaderDetails: {
'auth.timestamps.created': new Date('2022-01-01'),
},
});
const message = await groupLeader.post(`/groups/${group._id}/chat`, { message: testMessage });

View File

@@ -15,6 +15,10 @@ describe('POST /groups/:id/chat/seen', () => {
privacy: 'public',
},
members: 1,
leaderDetails: {
'auth.timestamps.created': new Date('2022-01-01'),
balance: 10,
},
});
guild = group;
@@ -51,6 +55,9 @@ describe('POST /groups/:id/chat/seen', () => {
privacy: 'private',
},
members: 1,
leaderDetails: {
'auth.timestamps.created': new Date('2022-01-01'),
},
});
party = group;

View File

@@ -18,6 +18,10 @@ describe('POST /groups/:id/chat/:id/clearflags', () => {
type: 'guild',
privacy: 'public',
},
leaderDetails: {
'auth.timestamps.created': new Date('2022-01-01'),
balance: 10,
},
});
groupWithChat = group;
@@ -65,6 +69,7 @@ describe('POST /groups/:id/chat/:id/clearflags', () => {
members: 1,
});
await members[0].update({ 'auth.timestamps.created': new Date('2022-01-01') });
let privateMessage = await members[0].post(`/groups/${group._id}/chat`, { message: 'Some message' });
privateMessage = privateMessage.message;

View File

@@ -37,6 +37,7 @@ describe('POST /groups/:groupId/leave', () => {
leader = groupLeader;
member = members[0]; // eslint-disable-line prefer-destructuring
memberCount = group.memberCount;
await members[0].update({ 'auth.timestamps.created': new Date('2022-01-01') });
});
it('prevents non members from leaving', async () => {
@@ -152,6 +153,10 @@ describe('POST /groups/:groupId/leave', () => {
type: 'guild',
},
invites: 1,
leaderDetails: {
'auth.timestamps.created': new Date('2022-01-01'),
balance: 10,
},
});
privateGuild = group;

View File

@@ -153,6 +153,7 @@ describe('POST /groups/:groupId/removeMember/:memberId', () => {
},
invites: 1,
members: 2,
leaderDetails: { 'auth.timestamps.created': new Date('2022-01-01') },
});
party = group;

View File

@@ -25,6 +25,7 @@ describe('Prevent multiple notifications', () => {
for (let i = 0; i < 4; i += 1) {
for (let memberIndex = 0; memberIndex < partyMembers.length; memberIndex += 1) {
await partyMembers[memberIndex].update({ 'auth.timestamps.created': new Date('2022-01-01') }); // eslint-disable-line no-await-in-loop
multipleChatMessages.push(
partyMembers[memberIndex].post(`/groups/${party._id}/chat`, { message: `Message ${i}_${memberIndex}` }),
);

View File

@@ -39,25 +39,38 @@ describe('POST /user/buy-quest/:key', () => {
}));
});
it('returns an error if quest prerequisites are not met', async () => {
const key = 'dilatoryDistress2';
it('returns an error if not all quest prerequisites are met', async () => {
const prerequisites = ['dilatoryDistress1', 'dilatoryDistress2'];
const key = 'dilatoryDistress3';
const achievementName1 = `achievements.quests.${prerequisites[0]}`;
await user.update({
[achievementName1]: true,
'stats.gp': 9999,
});
await expect(user.post(`/user/buy-quest/${key}`))
.to.eventually.be.rejected.and.eql({
code: 401,
error: 'NotAuthorized',
message: t('mustComplete', { quest: 'dilatoryDistress1' }),
message: t('mustComplete', { quest: prerequisites[1] }),
});
});
it('allows purchase of a quest if prerequisites are met', async () => {
const prerequisite = 'dilatoryDistress1';
const key = 'dilatoryDistress2';
const prerequisites = ['dilatoryDistress1', 'dilatoryDistress2'];
const key = 'dilatoryDistress3';
const item = content.quests[key];
const achievementName = `achievements.quests.${prerequisite}`;
const achievementName1 = `achievements.quests.${prerequisites[0]}`;
const achievementName2 = `achievements.quests.${prerequisites[1]}`;
await user.update({ [achievementName]: true, 'stats.gp': 9999 });
await user.update({
[achievementName1]: true,
[achievementName2]: true,
'stats.gp': 9999,
});
const res = await user.post(`/user/buy-quest/${key}`);
await user.sync();

View File

@@ -33,7 +33,7 @@ describe('shared.ops.buyQuestGems', () => {
pinnedGearUtils.removeItemByPath.restore();
});
context('successful purchase', () => {
context('single purchase', () => {
const userGemAmount = 10;
before(() => {
@@ -44,7 +44,7 @@ describe('shared.ops.buyQuestGems', () => {
user.pinnedItems.push({ type: 'quests', key: 'gryphon' });
});
it('purchases quests', async () => {
it('successfully purchases quest', async () => {
const key = 'gryphon';
await buyQuest(user, { params: { key } });
@@ -58,6 +58,28 @@ describe('shared.ops.buyQuestGems', () => {
await buyQuest(user, { params: { key } });
expect(user.items.quests[key]).to.equal(1);
expect(pinnedGearUtils.removeItemByPath.notCalled).to.equal(true);
});
it('errors if the user has not completed prerequisite quests', async () => {
const key = 'atom3';
user.achievements.quests.atom1 = 1;
try {
await buyQuest(user, { params: { key } });
} catch (err) {
expect(err).to.be.an.instanceof(NotAuthorized);
expect(err.message).to.equal(i18n.t('mustComplete', { quest: 'atom2' }));
expect(user.items.quests[key]).to.eql(undefined);
}
});
it('successfully purchases quest if user has completed all prerequisite quests', async () => {
const key = 'atom3';
user.achievements.quests.atom1 = 1;
user.achievements.quests.atom2 = 1;
await buyQuest(user, { params: { key } });
expect(user.items.quests[key]).to.equal(1);
expect(pinnedGearUtils.removeItemByPath.notCalled).to.equal(true);
});

View File

@@ -162,7 +162,9 @@ describe('shared.ops.buyQuest', () => {
}
});
it('does not buy a quest without completing previous quests', async () => {
it('returns error if user has not completed all prerequisite quests', async () => {
user.stats.gp = 9999;
user.achievements.quests.dilatoryDistress1 = 1;
try {
await buyQuest(user, {
params: {
@@ -175,4 +177,22 @@ describe('shared.ops.buyQuest', () => {
expect(user.items.quests).to.eql({});
}
});
it('successfully purchases quest if user has completed all prerequisite quests', async () => {
user.stats.gp = 500;
user.achievements.quests.dilatoryDistress1 = 1;
user.achievements.quests.dilatoryDistress2 = 1;
await buyQuest(user, {
params: {
key: 'dilatoryDistress3',
},
}, analytics);
expect(user.items.quests).to.eql({
dilatoryDistress3: 1,
});
expect(user.stats.gp).to.equal(100);
expect(analytics.track).to.be.calledOnce;
});
});

View File

@@ -11,6 +11,7 @@ if (process.env.LOAD_SERVER === '0') { // when the server is in a different proc
setupNconf('./config.json.example');
nconf.set('NODE_DB_URI', nconf.get('TEST_DB_URI'));
nconf.set('NODE_ENV', 'test');
nconf.set('ACCOUNT_MIN_CHAT_AGE', '2');
nconf.set('IS_TEST', true);
// We require src/server and not src/index because
// 1. nconf is already setup

View File

@@ -22,9 +22,9 @@
}
},
"@amplitude/analytics-connector": {
"version": "1.4.3",
"resolved": "https://registry.npmjs.org/@amplitude/analytics-connector/-/analytics-connector-1.4.3.tgz",
"integrity": "sha512-Ghu1UJn55Rn9eglF+ED7yOGXaeX3KY2qkQi9W9yqC02ItPvKfrybeVndweI1XtsiW0LvRpdA3uQEjuZEGunyLw==",
"version": "1.4.4",
"resolved": "https://registry.npmjs.org/@amplitude/analytics-connector/-/analytics-connector-1.4.4.tgz",
"integrity": "sha512-6JcE1nxrprJt6pHqqDQb7FXRqJmFHG7KJPe0jNZaAvfll4mWKVqZu8W9IV3XiN1P+xgHIV1NN+i3PLOAZWEhXg==",
"requires": {
"@amplitude/ua-parser-js": "0.7.31"
}
@@ -1799,39 +1799,39 @@
}
},
"@babel/plugin-proposal-optional-chaining": {
"version": "7.17.12",
"resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.17.12.tgz",
"integrity": "sha512-7wigcOs/Z4YWlK7xxjkvaIw84vGhDv/P1dFGQap0nHkc8gFKY/r+hXc8Qzf5k1gY7CvGIcHqAnOagVKJJ1wVOQ==",
"version": "7.18.6",
"resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.18.6.tgz",
"integrity": "sha512-PatI6elL5eMzoypFAiYDpYQyMtXTn+iMhuxxQt5mAXD4fEmKorpSI3PHd+i3JXBJN3xyA6MvJv7at23HffFHwA==",
"requires": {
"@babel/helper-plugin-utils": "^7.17.12",
"@babel/helper-skip-transparent-expression-wrappers": "^7.16.0",
"@babel/helper-plugin-utils": "^7.18.6",
"@babel/helper-skip-transparent-expression-wrappers": "^7.18.6",
"@babel/plugin-syntax-optional-chaining": "^7.8.3"
},
"dependencies": {
"@babel/helper-plugin-utils": {
"version": "7.17.12",
"resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.17.12.tgz",
"integrity": "sha512-JDkf04mqtN3y4iAbO1hv9U2ARpPyPL1zqyWs/2WG1pgSq9llHFjStX5jdxb84himgJm+8Ng+x0oiWF/nw/XQKA=="
"version": "7.18.6",
"resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.18.6.tgz",
"integrity": "sha512-gvZnm1YAAxh13eJdkb9EWHBnF3eAub3XTLCZEehHT2kWxiKVRL64+ae5Y6Ivne0mVHmMYKT+xWgZO+gQhuLUBg=="
},
"@babel/helper-skip-transparent-expression-wrappers": {
"version": "7.16.0",
"resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.16.0.tgz",
"integrity": "sha512-+il1gTy0oHwUsBQZyJvukbB4vPMdcYBrFHa0Uc4AizLxbq6BOYC51Rv4tWocX9BLBDLZ4kc6qUFpQ6HRgL+3zw==",
"version": "7.18.6",
"resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.18.6.tgz",
"integrity": "sha512-4KoLhwGS9vGethZpAhYnMejWkX64wsnHPDwvOsKWU6Fg4+AlK2Jz3TyjQLMEPvz+1zemi/WBdkYxCD0bAfIkiw==",
"requires": {
"@babel/types": "^7.16.0"
"@babel/types": "^7.18.6"
}
},
"@babel/helper-validator-identifier": {
"version": "7.16.7",
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz",
"integrity": "sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw=="
"version": "7.18.6",
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.18.6.tgz",
"integrity": "sha512-MmetCkz9ej86nJQV+sFCxoGGrUbU3q02kgLciwkrt9QqEB7cP39oKEY0PakknEO0Gu20SskMRi+AYZ3b1TpN9g=="
},
"@babel/types": {
"version": "7.18.0",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.18.0.tgz",
"integrity": "sha512-vhAmLPAiC8j9K2GnsnLPCIH5wCrPpYIVBCWRBFDCB7Y/BXLqi/O+1RSTTM2bsmg6U/551+FCf9PNPxjABmxHTw==",
"version": "7.18.7",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.18.7.tgz",
"integrity": "sha512-QG3yxTcTIBoAcQmkCs+wAPYZhu7Dk9rXKacINfNbdJDNERTbLQbHGyVG8q/YGMPeCJRIhSY0+fTc5+xuh6WPSQ==",
"requires": {
"@babel/helper-validator-identifier": "^7.16.7",
"@babel/helper-validator-identifier": "^7.18.6",
"to-fast-properties": "^2.0.0"
}
}
@@ -12131,11 +12131,11 @@
}
},
"@vue/cli-plugin-eslint": {
"version": "4.5.17",
"resolved": "https://registry.npmjs.org/@vue/cli-plugin-eslint/-/cli-plugin-eslint-4.5.17.tgz",
"integrity": "sha512-bVNDP+SuWcuJrBMc+JLaKvlxx25XKIlZBa+zzFnxhHZlwPZ7CeBD3e2wnsygJyPoKgDZcZwDgmEz1BZzMEjsNw==",
"version": "4.5.19",
"resolved": "https://registry.npmjs.org/@vue/cli-plugin-eslint/-/cli-plugin-eslint-4.5.19.tgz",
"integrity": "sha512-53sa4Pu9j5KajesFlj494CcO8vVo3e3nnZ1CCKjGGnrF90id1rUeepcFfz5XjwfEtbJZp2x/NoX/EZE6zCzSFQ==",
"requires": {
"@vue/cli-shared-utils": "^4.5.17",
"@vue/cli-shared-utils": "^4.5.19",
"eslint-loader": "^2.2.1",
"globby": "^9.2.0",
"inquirer": "^7.1.0",
@@ -12144,9 +12144,9 @@
},
"dependencies": {
"@vue/cli-shared-utils": {
"version": "4.5.17",
"resolved": "https://registry.npmjs.org/@vue/cli-shared-utils/-/cli-shared-utils-4.5.17.tgz",
"integrity": "sha512-VoFNdxvTW4vZu3ne+j1Mf7mU99J2SAoRVn9XPrsouTUUJablglM8DASk7Ixhsh6ymyL/W9EADQFR6Pgj8Ujjuw==",
"version": "4.5.19",
"resolved": "https://registry.npmjs.org/@vue/cli-shared-utils/-/cli-shared-utils-4.5.19.tgz",
"integrity": "sha512-JYpdsrC/d9elerKxbEUtmSSU6QRM60rirVubOewECHkBHj+tLNznWq/EhCjswywtePyLaMUK25eTqnTSZlEE+g==",
"requires": {
"@achrinza/node-ipc": "9.2.2",
"@hapi/joi": "^15.0.1",
@@ -13086,11 +13086,11 @@
"integrity": "sha1-l6ERlkmyEa0zaR2fn0hqjsn74KM="
},
"amplitude-js": {
"version": "8.18.4",
"resolved": "https://registry.npmjs.org/amplitude-js/-/amplitude-js-8.18.4.tgz",
"integrity": "sha512-Nk4ymaw9iGf1Be/fGuuH7H/QnUJceD2RYGdode8ZAApw6jHlm9QZCoYoVRrNPdgfb3yJz3P84EPh/4xM+/98/w==",
"version": "8.18.5",
"resolved": "https://registry.npmjs.org/amplitude-js/-/amplitude-js-8.18.5.tgz",
"integrity": "sha512-s43q4qKd7kvhYESQhYvyKDKUM1PpyAyoOFFlyMuFfQHRxyeDmZRhcfzrKnOhbrLhFxSWtPc0VEeh9tajJRNe5Q==",
"requires": {
"@amplitude/analytics-connector": "1.4.3",
"@amplitude/analytics-connector": "1.4.4",
"@amplitude/ua-parser-js": "0.7.31",
"@amplitude/utils": "^1.0.5",
"@babel/runtime": "^7.3.4",
@@ -13697,9 +13697,12 @@
"integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg=="
},
"async": {
"version": "3.2.3",
"resolved": "https://registry.npmjs.org/async/-/async-3.2.3.tgz",
"integrity": "sha512-spZRyzKL5l5BZQrr/6m/SqFdBN0q3OCI0f9rjfBzCMBIP4p75P620rR3gTmaksNOhmzgdxcaxdNfMy6anrbM0g=="
"version": "2.6.4",
"resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz",
"integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==",
"requires": {
"lodash": "^4.17.14"
}
},
"async-each": {
"version": "1.0.3",
@@ -15836,9 +15839,9 @@
}
},
"core-js": {
"version": "3.22.8",
"resolved": "https://registry.npmjs.org/core-js/-/core-js-3.22.8.tgz",
"integrity": "sha512-UoGQ/cfzGYIuiq6Z7vWL1HfkE9U9IZ4Ub+0XSiJTCzvbZzgPA69oDF2f+lgJ6dFFLEdjW5O6svvoKzXX23xFkA=="
"version": "3.23.5",
"resolved": "https://registry.npmjs.org/core-js/-/core-js-3.23.5.tgz",
"integrity": "sha512-7Vh11tujtAZy82da4duVreQysIoO2EvVrur7y6IzZkH1IHPSekuDi8Vuw1+YKjkbfWLRD7Nc9ICQ/sIUDutcyg=="
},
"core-js-compat": {
"version": "3.11.0",
@@ -20975,7 +20978,7 @@
"find-cache-dir": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-0.1.1.tgz",
"integrity": "sha1-yN765XyKUqinhPnjHFfHQumToLk=",
"integrity": "sha512-Z9XSBoNE7xQiV6MSgPuCfyMokH2K7JdpRkOYE1+mu3d4BFJtx3GW+f6Bo4q8IX6rlf5MYbLBKW0pjl2cWdkm2A==",
"requires": {
"commondir": "^1.0.1",
"mkdirp": "^0.5.1",
@@ -20985,7 +20988,7 @@
"find-up": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz",
"integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=",
"integrity": "sha512-jvElSjyuo4EMQGoTwo1uJU5pQMwTW5lS1x05zzfJuTIyLR3zwO27LYrxNg+dlvKpGOuGy/MzBdXh80g0ve5+HA==",
"requires": {
"path-exists": "^2.0.0",
"pinkie-promise": "^2.0.0"
@@ -20994,7 +20997,7 @@
"path-exists": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz",
"integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=",
"integrity": "sha512-yTltuKuhtNeFJKa1PiRzfLAU5182q1y4Eb4XCJ3PBqyzEDkAZRzBrKKBct682ls9reBVHf9udYLN5Nd+K1B9BQ==",
"requires": {
"pinkie-promise": "^2.0.0"
}
@@ -21002,7 +21005,7 @@
"pkg-dir": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-1.0.0.tgz",
"integrity": "sha1-ektQio1bstYp1EcFb/TpyTFM89Q=",
"integrity": "sha512-c6pv3OE78mcZ92ckebVDqg0aWSoKhOTbwCV6qbCWMk546mAL9pZln0+QsN/yQ7fkucd4+yJPLrCBXNt8Ruk+Eg==",
"requires": {
"find-up": "^1.0.0"
}
@@ -21926,9 +21929,9 @@
}
},
"moment": {
"version": "2.29.3",
"resolved": "https://registry.npmjs.org/moment/-/moment-2.29.3.tgz",
"integrity": "sha512-c6YRvhEo//6T2Jz/vVtYzqBzwvPT95JBQ+smCytzf7c50oMZRsR/a4w88aD34I+/QVSfnoAnSBFPJHItlOMJVw=="
"version": "2.29.4",
"resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz",
"integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w=="
},
"move-concurrently": {
"version": "1.0.1",
@@ -22035,6 +22038,11 @@
"color-convert": "^2.0.1"
}
},
"async": {
"version": "3.2.4",
"resolved": "https://registry.npmjs.org/async/-/async-3.2.4.tgz",
"integrity": "sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ=="
},
"cliui": {
"version": "7.0.4",
"resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz",
@@ -23119,14 +23127,6 @@
"mkdirp": "^0.5.5"
},
"dependencies": {
"async": {
"version": "2.6.3",
"resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz",
"integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==",
"requires": {
"lodash": "^4.17.14"
}
},
"debug": {
"version": "3.2.7",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
@@ -26883,7 +26883,7 @@
"strip-indent": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-2.0.0.tgz",
"integrity": "sha1-XvjbKV0B5u1sv3qrlpmNeCJSe2g="
"integrity": "sha512-RsSNPLpq6YUL7QYy44RnPVTn/lcVZtb48Uof3X5JLbF4zD/Gs7ZFDv2HWol+leoQN2mT86LAzSshGfkTlSOpsA=="
},
"strip-json-comments": {
"version": "2.0.1",
@@ -29477,7 +29477,7 @@
"cross-spawn": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz",
"integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=",
"integrity": "sha512-pTgQJ5KC0d2hcY8eyL1IzlBPYjTkyH72XRZPnLyKus2mBfNjQs3klqbJU2VILqZryAZUt9JOb3h/mWMy23/f5A==",
"requires": {
"lru-cache": "^4.0.1",
"shebang-command": "^1.2.0",
@@ -29487,7 +29487,7 @@
"execa": {
"version": "0.8.0",
"resolved": "https://registry.npmjs.org/execa/-/execa-0.8.0.tgz",
"integrity": "sha1-2NdrvBtVIX7RkP1t1J08d07PyNo=",
"integrity": "sha512-zDWS+Rb1E8BlqqhALSt9kUhss8Qq4nN3iof3gsOdyINksElaPyNBtKUMTR62qhvgVWR0CqCX7sdnKe4MnUbFEA==",
"requires": {
"cross-spawn": "^5.0.1",
"get-stream": "^3.0.0",
@@ -29501,7 +29501,7 @@
"get-stream": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz",
"integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ="
"integrity": "sha512-GlhdIUuVakc8SJ6kK0zAFbiGzRFzNnY4jUuEbV9UROo4Y+0Ny4fjvcZFVTeDA4odpFyOQzaw6hXukJSq/f28sQ=="
},
"lru-cache": {
"version": "4.1.5",
@@ -29515,12 +29515,12 @@
"normalize-path": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-1.0.0.tgz",
"integrity": "sha1-MtDkcvkf80VwHBWoMRAY07CpA3k="
"integrity": "sha512-7WyT0w8jhpDStXRq5836AMmihQwq2nrUVQrgjvUo/p/NZf9uy/MeJ246lBJVmWuYXMlJuG9BNZHF0hWjfTbQUA=="
},
"yallist": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz",
"integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI="
"integrity": "sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A=="
}
}
},

View File

@@ -20,19 +20,19 @@
"@storybook/addons": "6.5.9",
"@storybook/vue": "6.3.13",
"@vue/cli-plugin-babel": "^4.5.15",
"@vue/cli-plugin-eslint": "^4.5.17",
"@vue/cli-plugin-eslint": "^4.5.19",
"@vue/cli-plugin-router": "^4.5.15",
"@vue/cli-plugin-unit-mocha": "^4.5.15",
"@vue/cli-service": "^4.5.15",
"@vue/test-utils": "1.0.0-beta.29",
"amplitude-js": "^8.18.4",
"amplitude-js": "^8.18.5",
"axios": "^0.25.0",
"axios-progress-bar": "^1.2.0",
"babel-eslint": "^10.1.0",
"bootstrap": "^4.6.0",
"bootstrap-vue": "^2.22.0",
"chai": "^4.3.6",
"core-js": "^3.22.8",
"core-js": "^3.23.5",
"dompurify": "^2.3.8",
"eslint": "^6.8.0",
"eslint-config-habitrpg": "^6.2.0",
@@ -44,7 +44,7 @@
"intro.js": "^5.1.0",
"jquery": "^3.6.0",
"lodash": "^4.17.21",
"moment": "^2.29.3",
"moment": "^2.29.4",
"nconf": "^0.12.0",
"sass": "^1.34.0",
"sass-loader": "^8.0.2",
@@ -65,6 +65,6 @@
"webpack": "^4.46.0"
},
"devDependencies": {
"@babel/plugin-proposal-optional-chaining": "^7.17.12"
"@babel/plugin-proposal-optional-chaining": "^7.18.6"
}
}

View File

@@ -414,7 +414,15 @@ export default {
this.$store.state.isUserLoaded = true;
Analytics.setUser();
Analytics.updateUser();
return axios.get('/api/v4/i18n/browser-script', { language: this.user.preferences.language });
return axios.get('/api/v4/i18n/browser-script',
{
language: this.user.preferences.language,
headers: {
'Cache-Control': 'no-cache',
Pragma: 'no-cache',
Expires: '0',
},
});
}).then(() => {
const i18nData = window && window['habitica-i18n'];
this.$loadLocale(i18nData);

View File

@@ -625,6 +625,11 @@
width: 141px;
height: 147px;
}
.background_bioluminescent_waves {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/background_bioluminescent_waves.png');
width: 141px;
height: 147px;
}
.background_birch_forest {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/background_birch_forest.png');
width: 141px;
@@ -1884,11 +1889,21 @@
width: 141px;
height: 147px;
}
.background_underwater_cave {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/background_underwater_cave.png');
width: 141px;
height: 147px;
}
.background_underwater_ruins {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/background_underwater_ruins.png');
width: 141px;
height: 147px;
}
.background_underwater_statues {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/background_underwater_statues.png');
width: 141px;
height: 147px;
}
.background_underwater_vents {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/background_underwater_vents.png');
width: 141px;
@@ -2151,6 +2166,11 @@
width: 68px;
height: 68px;
}
.icon_background_bioluminescent_waves {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/icon_background_bioluminescent_waves.png');
width: 68px;
height: 68px;
}
.icon_background_birch_forest {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/icon_background_birch_forest.png');
width: 68px;
@@ -3420,11 +3440,21 @@
width: 68px;
height: 68px;
}
.icon_background_underwater_cave {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/icon_background_underwater_cave.png');
width: 68px;
height: 68px;
}
.icon_background_underwater_ruins {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/icon_background_underwater_ruins.png');
width: 68px;
height: 68px;
}
.icon_background_underwater_statues {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/icon_background_underwater_statues.png');
width: 68px;
height: 68px;
}
.icon_background_underwater_vents {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/icon_background_underwater_vents.png');
width: 68px;
@@ -18145,6 +18175,11 @@
width: 90px;
height: 90px;
}
.broad_armor_armoire_fancyPirateSuit {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/broad_armor_armoire_fancyPirateSuit.png');
width: 114px;
height: 90px;
}
.broad_armor_armoire_farrierOutfit {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/broad_armor_armoire_farrierOutfit.png');
width: 90px;
@@ -18590,6 +18625,11 @@
width: 90px;
height: 90px;
}
.head_armoire_fancyPirateHat {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/head_armoire_fancyPirateHat.png');
width: 114px;
height: 90px;
}
.head_armoire_fiddlersCap {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/head_armoire_fiddlersCap.png');
width: 114px;
@@ -19175,6 +19215,11 @@
width: 114px;
height: 87px;
}
.shield_armoire_treasureMap {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/shield_armoire_treasureMap.png');
width: 114px;
height: 90px;
}
.shield_armoire_trustyUmbrella {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/shield_armoire_trustyUmbrella.png');
width: 114px;
@@ -19325,6 +19370,11 @@
width: 68px;
height: 68px;
}
.shop_armor_armoire_fancyPirateSuit {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/shop_armor_armoire_fancyPirateSuit.png');
width: 68px;
height: 68px;
}
.shop_armor_armoire_farrierOutfit {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/shop_armor_armoire_farrierOutfit.png');
width: 68px;
@@ -19785,6 +19835,11 @@
width: 68px;
height: 68px;
}
.shop_head_armoire_fancyPirateHat {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/shop_head_armoire_fancyPirateHat.png');
width: 68px;
height: 68px;
}
.shop_head_armoire_fiddlersCap {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/shop_head_armoire_fiddlersCap.png');
width: 68px;
@@ -20370,6 +20425,11 @@
width: 68px;
height: 68px;
}
.shop_shield_armoire_treasureMap {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/shop_shield_armoire_treasureMap.png');
width: 68px;
height: 68px;
}
.shop_shield_armoire_trustyUmbrella {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/shop_shield_armoire_trustyUmbrella.png');
width: 68px;
@@ -20960,6 +21020,11 @@
width: 90px;
height: 90px;
}
.slim_armor_armoire_fancyPirateSuit {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/slim_armor_armoire_fancyPirateSuit.png');
width: 114px;
height: 90px;
}
.slim_armor_armoire_farrierOutfit {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/slim_armor_armoire_farrierOutfit.png');
width: 90px;
@@ -26830,6 +26895,36 @@
width: 68px;
height: 68px;
}
.broad_armor_mystery_202207 {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/broad_armor_mystery_202207.png');
width: 117px;
height: 120px;
}
.head_mystery_202207 {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/head_mystery_202207.png');
width: 117px;
height: 120px;
}
.shop_armor_mystery_202207 {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/shop_armor_mystery_202207.png');
width: 68px;
height: 68px;
}
.shop_head_mystery_202207 {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/shop_head_mystery_202207.png');
width: 68px;
height: 68px;
}
.shop_set_mystery_202207 {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/shop_set_mystery_202207.png');
width: 68px;
height: 68px;
}
.slim_armor_mystery_202207 {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/slim_armor_mystery_202207.png');
width: 117px;
height: 120px;
}
.broad_armor_mystery_301404 {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/broad_armor_mystery_301404.png');
width: 90px;

View File

@@ -82,7 +82,7 @@ input, textarea, input.form-control, textarea.form-control {
}
}
/** Colored Input-Groups, ignoring checklist */
// Colored Input-Groups, ignoring checklist
.input-group:not(.checklist-group) {
border-radius: 2px;
border: solid 1px $gray-400;
@@ -100,7 +100,7 @@ input, textarea, input.form-control, textarea.form-control {
}
}
/** Generic Input Group Styles */
// Generic Input Group Styles
.input-group {
height: 2rem;
@@ -179,10 +179,11 @@ input, textarea, input.form-control, textarea.form-control {
padding-left: 0px;
}
// Checkboxes and radios
// used in checkboxes and radios
$bg-focused-active-control: #4f2993;
$bg-disabled-control: #34303a;
// custom control
.custom-control {
margin-bottom: .5rem;
@@ -205,6 +206,7 @@ $bg-disabled-control: #34303a;
}
}
// checkboxes
.custom-checkbox {
.custom-control-label::before {
border-radius: 2px;
@@ -280,11 +282,26 @@ $bg-disabled-control: #34303a;
padding-left: 36px;
}
// radio buttons
$bg-color: $purple-400;
// svg for the purple dot
@mixin custom-radio-checked-icon ($bg-color) {
background-image: str-replace(url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3E%3Ccircle r='3' fill='#{$bg-color}'/%3E%3C/svg%3E"), "#", "%23");
}
.custom-radio .custom-control-input {
opacity: 0;
margin: 15px 25px 34px 25px;
// outside circle
&:checked~.custom-control-label::before {
background-color: $gray-700;
background-size: 12px 12px;
border-color: $purple-400;
}
// checked indicator
&:checked~.custom-control-label::after {
@include custom-radio-checked-icon($purple-400);
width: 18px;
@@ -292,51 +309,84 @@ $bg-disabled-control: #34303a;
background-size: 12px 12px;
}
&:checked~.custom-control-label::before {
background-color: $gray-700;
background-size: 12px 12px;
border-color: $purple-400;
}
&:active~.custom-control-label::before {
background-color: inherit;
}
&:focus:not(:checked):not(:disabled)~.custom-control-label::before, &:active:not(:checked):not(:disabled)~.custom-control-label::before {
box-shadow: 0 0 0 6px rgba($bg-focused-active-control, 0.1);
// focus / not checked / not disabled
&:focus:not(:checked):not(:disabled)~.custom-control-label::before,
&:active:not(:checked):not(:disabled)~.custom-control-label::before {
border: 2px solid $gray-300;
box-shadow: 0 0 0 2px rgba(146, 92, 243, 0.5);
}
&:focus:checked:not(:disabled)~.custom-control-label::before, &:active:checked:not(:disabled)~.custom-control-label::before {
box-shadow: 0 0 0 6px rgba($bg-focused-active-control, 0.1);
border-color: $purple-400;
background-color: rgba($bg-focused-active-control, 0.1);
// focus / checked / not disabled
&:focus:checked:not(:disabled)~.custom-control-label::before,
&:active:checked:not(:disabled)~.custom-control-label::before {
border: 2px solid $purple-400;
box-shadow: 0 0 0 2px rgba(146, 92, 243, 0.5);
}
&:disabled:checked~.custom-control-label::before {
border-color: $gray-400;
background-color: transparent;
// hover / not checked / not disabled
&:hover:not(:checked):not(:disabled)~.custom-control-label::before,
&:active:not(:checked):not(:disabled)~.custom-control-label::before {
width: 18px;
height: 18px;
background: 50%/50% 50% no-repeat;
@include custom-radio-checked-icon($purple-400);
background-size: 12px 12px;
border: solid 2px $purple-400;
}
&:disabled:checked~.custom-control-label::after {
// hover / checked / not disabled
&:hover:checked:not(:disabled)~.custom-control-label::before,
&:active::checked:not(:disabled)~.custom-control-label::before {
width: 18px;
height: 18px;
background: 50%/50% 50% no-repeat;
@include custom-radio-checked-icon($gray-400);
background-size: 12px 12px;
border: solid 2px $purple-300;
}
// disabled / checked / before
&:disabled:checked~.custom-control-label::before {
background: 50%/50% 50% no-repeat;
@include custom-radio-checked-icon($gray-300);
border: 2px solid $gray-200;
background-color: transparent;
opacity: 0.75;
}
// disabled / checked / after
&:disabled:checked~.custom-control-label::after {
background: 50%/50% 50% no-repeat;
@include custom-radio-checked-icon($gray-300);
width: 18px;
height: 18px;
background-size: 12px 12px;
}
// disabled / not checked / before
&:disabled:not(:checked)~.custom-control-label::before {
border-color: $gray-300;
background-color: transparent;
background-color: $gray-600;
border: 2px solid $gray-200;
}
&:focus:disabled~.custom-control-label::before, &:active:disabled~.custom-control-label::before {
box-shadow: 0 0 0 6px rgba($bg-disabled-control, 0.1);
border-color: $gray-300;
// focus and disabled / not checked / before
&:focus:disabled~.custom-control-label::before,
&:active:disabled~.custom-control-label::before {
background-color: rgba($bg-disabled-control, 0.1);
box-shadow: 0 0 0 6px rgba($bg-disabled-control, 0.1);
border: 2px solid $gray-200;
}
&:focus:disabled:checked~.custom-control-label::before, &:active:disabled:checked~.custom-control-label::before {
border-color: $gray-400;
// focus and disabled / checked / before
&:focus:disabled:checked~.custom-control-label::before,
&:active:disabled:checked~.custom-control-label::before {
background: 50%/50% 50% no-repeat;
@include custom-radio-checked-icon($gray-300);
border: 2px solid $gray-200;
}
}

View File

@@ -0,0 +1,27 @@
<svg width="176" height="67" viewBox="0 0 176 67" xmlns="http://www.w3.org/2000/svg">
<g fill="none" fill-rule="evenodd">
<path fill="#77F4C7" d="M35.667 11.667 40 9.5l-4.333-2.167L33.5 3l-2.167 4.333L27 9.5l4.333 2.167L33.5 16z"/>
<path fill="#BDA8FF" d="M24.667 38.667 30 36l-5.333-2.667L22 28l-2.667 5.333L14 36l5.333 2.667L22 44z"/>
<path fill="#8EEDF6" d="M35.667 63.667 39 62l-3.333-1.667L34 57l-1.667 3.333L29 62l3.333 1.667L34 67z"/>
<path fill="#FFBE5D" d="M6.667 49.667 10 48l-3.333-1.667L5 43l-1.667 3.333L0 48l3.333 1.667L5 53z"/>
<path fill="#FFB6B8" d="M5.667 20.667 8 19.5l-2.333-1.167L4.5 16l-1.167 2.333L1 19.5l2.333 1.167L4.5 23z"/>
<g>
<path fill="#77F4C7" d="M140.333 11.667 136 9.5l4.333-2.167L142.5 3l2.167 4.333L149 9.5l-4.333 2.167L142.5 16z"/>
<path fill="#BDA8FF" d="M151.333 38.667 146 36l5.333-2.667L154 28l2.667 5.333L162 36l-5.333 2.667L154 44z"/>
<path fill="#8EEDF6" d="M140.333 63.667 137 62l3.333-1.667L142 57l1.667 3.333L147 62l-3.333 1.667L142 67z"/>
<path fill="#FFBE5D" d="M169.333 49.667 166 48l3.333-1.667L171 43l1.667 3.333L176 48l-3.333 1.667L171 53z"/>
<path fill="#FFB6B8" d="M170.333 20.667 168 19.5l2.333-1.167L171.5 16l1.167 2.333L175 19.5l-2.333 1.167L171.5 23z"/>
</g>
<g>
<path d="M81.117 13.904c-2.139-4.838-6.274-9.113-11.25-9.324-4.976-.211-7.828 3.779-6.367 7.309 1.461 3.53 4.94 4.177 16.227 7.202 3.204.858 3.528-.35 1.39-5.187z" stroke="#22AEB7" stroke-width="4"/>
<path d="M93.833 13.904c2.138-4.838 6.273-9.113 11.25-9.324 4.975-.211 7.828 3.779 6.367 7.309-1.462 3.53-4.94 4.177-16.227 7.202-3.205.858-3.528-.35-1.39-5.187z" stroke="#38C9C6" stroke-width="4"/>
<path d="M87.128 11c-9.738 0-3.907 11.145 0 11.145 3.908 0 9.74-11.145 0-11.145z" fill="#46DDDA"/>
<path fill="#6133B4" d="M62 33h52v34H62zM56 21h64v12H56z"/>
<path fill-opacity=".5" fill="#FFF" style="mix-blend-mode:soft-light" d="M32 30h26v34H32z" transform="translate(56 3)"/>
<path fill="#8EEDF6" d="M88 33h6v34h-6z"/>
<path fill="#3BCAD7" d="M82 33h6v34h-6zM76 21h12v12H76z"/>
<path fill="#8EEDF6" d="M88 21h12v12H88z"/>
<path fill-opacity=".2" fill="#000" style="mix-blend-mode:multiply" d="M6 30h26v6H6zM20 18h12v6H20zM0 24h20v6H0zM44 24h20v6H44zM32 18h12v6H32zM6 58h26v6H6zM32 30h26v6H32zM32 58h26v6H32z" transform="translate(56 3)"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

View File

@@ -1,5 +1,11 @@
<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 12 12">
<g fill="none" fill-rule="evenodd" stroke="#A5A1AC" stroke-width="2">
<path d="M1 11L11 1M11 11L1 1"/>
<?xml version="1.0" encoding="UTF-8"?>
<svg width="16px" height="16px" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>Icon/Close</title>
<g id="Modals" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="Shop-Modals" transform="translate(-183.000000, -655.000000)" fill="#878190" fill-rule="nonzero">
<g id="Icon/Close" transform="translate(183.000000, 655.000000)">
<polygon id="Mask" points="12.1973467 2 14 3.80265326 9.80187117 8 14 12.1973467 12.1973467 14 8 9.80187117 3.80265326 14 2 12.1973467 6.19812883 8 2 3.80265326 3.80265326 2 8 6.19812883"></polygon>
</g>
</g>
</g>
</svg>
</svg>

Before

Width:  |  Height:  |  Size: 215 B

After

Width:  |  Height:  |  Size: 747 B

View File

@@ -122,6 +122,11 @@
font-weight: bold;
}
.custom-control-input {
z-index: -1;
opacity: 0;
}
.box:hover {
cursor: pointer;
opacity: 0.7;

View File

@@ -3,7 +3,7 @@
<creator-intro />
<profileModal />
<report-flag-modal />
<send-gems-modal />
<send-gift-modal />
<select-user-modal />
<b-navbar
id="habitica-menu"
@@ -747,7 +747,7 @@ import creatorIntro from '../creatorIntro';
import notificationMenu from './notificationsDropdown';
import profileModal from '../userMenu/profileModal';
import reportFlagModal from '../chat/reportFlagModal';
import sendGemsModal from '@/components/payments/sendGemsModal';
import sendGiftModal from '@/components/payments/sendGiftModal';
import selectUserModal from '@/components/payments/selectUserModal';
import sync from '@/mixins/sync';
import userDropdown from './userDropdown';
@@ -759,7 +759,7 @@ export default {
notificationMenu,
profileModal,
reportFlagModal,
sendGemsModal,
sendGiftModal,
selectUserModal,
userDropdown,
},

View File

@@ -4,7 +4,7 @@
:class="{ condensed, expanded, 'd-flex': isHeader, row: !isHeader, }"
@click="showMemberModal(member)"
>
<div :class="{ 'col-4': !isHeader }">
<div class="avatar-container" :class="{ 'col-4': !isHeader }">
<avatar
:member="member"
:hide-class-badge="classBadgePosition !== 'under-avatar'"
@@ -92,6 +92,10 @@
.member-details {
white-space: nowrap;
transition: all 0.15s ease-out;
.avatar-container {
margin-bottom: 20px;
}
}
.member-stats {

View File

@@ -198,7 +198,7 @@ export default {
appState.newGroup = false;
appState.group = pick(this.amazonPayments.group, ['_id', 'memberCount', 'name']);
}
} else if (paymentType.indexOf('gift-') === 0) {
} else if (paymentType && paymentType.indexOf('gift-') === 0) {
appState.gift = this.amazonPayments.gift;
appState.giftReceiver = this.amazonPayments.giftReceiver;
} else if (paymentType === 'gems') {

View File

@@ -1,5 +1,6 @@
<template>
<div class="payments-column mx-auto mt-auto">
<h4>{{ $t('choosePaymentMethod') }}</h4>
<button
v-if="stripeAvailable"
class="btn btn-primary payment-button payment-item with-icon"
@@ -80,6 +81,13 @@
cursor: default !important;
}
}
h4 {
font-size: 0.875rem;
font-weight: bold;
text-align: center;
margin-bottom: 1rem;
}
</style>
<script>

View File

@@ -14,15 +14,44 @@
</div>
<h2
v-else
class="ml-2"
class="d-flex flex-column mx-auto align-items-center"
>
{{ $t('sendGift') }}
{{ $t('sendAGift') }}
</h2>
<div
v-if="currentEvent && currentEvent.promo === 'g1g1'"
class="g1g1-margin d-flex flex-column align-items-center"
>
<div
class="svg-big-gift"
v-once
v-html="icons.bigGift"
></div>
</div>
<div
v-else
class="d-flex flex-column align-items-center">
<div
class="svg-big-gift"
v-once
v-html="icons.bigGift"
></div>
</div>
<div class="d-flex flex-column align-items-center">
<div
class="modal-close"
v-if="currentEvent && currentEvent.promo === 'g1g1'"
class="g1g1-modal-close"
@click="close()"
>
<div
class="g1g1-svg-icon"
v-html="icons.close"
></div>
</div>
<div
v-else
class="modal-close"
@click="close()">
<div
class="svg-icon"
v-html="icons.close"
@@ -42,6 +71,7 @@
v-model="userSearchTerm"
class="form-control"
type="text"
ref="textBox"
:placeholder="$t('usernameOrUserId')"
:class="{
'input-valid': foundUser._id,
@@ -70,15 +100,20 @@
<div
v-else
>
{{ $t('selectGift') }}
{{ $t('next') }}
</div>
</button>
<a
class="cancel-link mx-auto mt-3"
@click="close()"
<div
v-if="currentEvent && currentEvent.promo ==='g1g1'"
class="g1g1-cancel d-flex justify-content-center"
v-html="$t('cancel')"
@click="close()"
>
{{ $t('cancel') }}
</a>
{{ $t('cancel') }}
</div>
<div
v-else>
</div>
</div>
</div>
</div>
@@ -110,13 +145,16 @@
@import '~@/assets/scss/mixins.scss';
#select-user-modal {
.modal-content {
width:448px;
}
.input-group {
margin-top: 0rem;
}
.modal-dialog {
width: 29.5rem;
margin-top: 25vh;
width: 448px;
}
.modal-footer {
@@ -126,7 +164,16 @@
margin: 0rem 0.25rem 0.25rem 0.25rem;
}
}
}
body.modal-open .modal {
display: flex !important;
height: 100%;
}
body.modal-open .modal .modal-dialog {
margin: auto;
}
}
</style>
<style lang="scss" scoped>
@@ -146,12 +193,12 @@
.g1g1 {
background-image: url('~@/assets/images/g1g1-send.png');
background-size: 472px 152px;
width: 470px;
background-size: 446px 152px;
width: 446px;
height: 152px;
margin: -1rem 0rem 0rem -1rem;
border-radius: 0.3rem 0.3rem 0rem 0rem;
padding: 1.5rem;
margin: -16px 0px 0px -16px;
border-radius: 4.8px 4.8px 0px 0px;
padding: 24px;
color: $white;
h1 {
@@ -169,6 +216,16 @@
}
}
.g1g1-margin {
margin-top: 24px;
}
.g1g1-cancel {
margin-top: 16px;
color: $blue-10;
cursor: pointer;
}
.g1g1-fine-print {
color: $gray-100;
background-color: $gray-700;
@@ -176,6 +233,29 @@
line-height: 1.33;
}
.g1g1-modal-close {
position: absolute;
width: 18px;
height: 18px;
padding: 4px;
right: 16px;
top: 16px;
cursor: pointer;
.g1g1-svg-icon {
width: 12px;
height: 12px;
& ::v-deep svg path {
fill: #FFFFFF;
}
}
}
.g1g1-modal-dialog {
margin-top: 10vh;
}
.input-error {
color: $red-50;
font-size: 90%;
@@ -192,6 +272,18 @@
border-color: $purple-500;
}
h2 {
font-size: 1.25rem;
line-height: 1.75rem;
color: $purple-300;
padding-top: 1rem;
}
.svg-big-gift {
width: 176px;
height: 64px;
}
.modal-close {
position: absolute;
width: 18px;
@@ -206,14 +298,17 @@
height: 12px;
}
}
</style>
<script>
// import { nextTick } from 'vue'; // may not need this? I don't know!
import debounce from 'lodash/debounce';
import find from 'lodash/find';
import isUUID from 'validator/lib/isUUID';
import { mapState } from '@/libs/store';
import closeIcon from '@/assets/svg/close.svg';
import bigGiftIcon from '@/assets/svg/big-gift.svg';
export default {
data () {
@@ -223,6 +318,7 @@ export default {
foundUser: {},
icons: Object.freeze({
close: closeIcon,
bigGift: bigGiftIcon,
}),
};
},
@@ -281,7 +377,7 @@ export default {
this.foundUser = result;
}, 500),
selectUser () {
this.$root.$emit('habitica::send-gems', this.foundUser);
this.$root.$emit('habitica::send-gift', this.foundUser);
this.close();
},
onHide () {

View File

@@ -0,0 +1,659 @@
<template>
<b-modal
id="send-gift"
:hide-footer="true"
:hide-header="true"
size="md"
@hide="onHide()"
>
<div>
<!-- header -->
<div
class="modal-close"
@click="close()"
>
<div
class="icon-close"
v-html="icons.closeIcon"
>
</div>
</div>
<div>
<h2 class="d-flex flex-column mx-auto align-items-center">
{{ $t('sendAGift') }}
</h2>
</div>
<!-- user avatar -->
<div
v-if="userReceivingGift"
class="modal-body"
>
<avatar
:member="userReceivingGift"
:hideClassBadge="true"
class="d-flex flex-column mx-auto align-items-center"
/>
<div class="avatar-spacer"></div>
<div class="d-flex flex-column mx-auto align-items-center display-name">
<!-- user display name and username -->
<user-link
:user-id="displayName"
:name="displayName"
:backer="userBacker"
:contributor="userContributor"
:class="display-name"
/>
</div>
<div class="d-flex flex-column mx-auto align-items-center user-name">
@{{ userName }}
</div>
</div>
<!-- menu area -->
<div class="row">
<div class="col-md-8 offset-md-2 text-center nav">
<div
class="nav-link"
:class="{active: selectedPage === 'subscription'}"
@click="selectPage('subscription')"
>
{{ $t('subscription') }}
</div>
<div
class="nav-link"
:class="{active: selectedPage !== 'subscription'}"
@click="selectPage('buyGems')"
>
{{ $t('gems') }}
</div>
</div>
</div>
<!-- subscriber block -->
<subscription-options
v-show="selectedPage === 'subscription'"
class="subscribe-option"
:userReceivingGift="userReceivingGift"
/>
<!-- gem block -->
<div
v-show="selectedPage === 'buyGems'"
>
<div class="gem-group">
<!-- buy gems with money -->
<label v-once>
{{ $t('howManyGemsPurchase') }}
</label>
<div class="d-flex flex-row align-items-center justify-content-center">
<div
class="gray-circle"
@click="gift.gems.amount <= 0
? gift.gems.amount = 0
: gift.gems.amount--"
>
<div
class="icon-negative"
v-html="icons.negativeIcon"
></div>
</div>
<div class="input-group">
<div class="input-group-prepend input-group-icon align-items-center">
<div
class="icon-gem"
v-html="icons.gemIcon"
></div>
</div>
<input
id="gemsForm"
v-model.number="gift.gems.amount"
class="form-control"
max="9999"
>
</div>
<div
class="gray-circle"
@click="gift.gems.amount++"
>
<div
class="icon-positive"
v-html="icons.positiveIcon"
></div>
</div>
</div>
<!-- the word "total" -->
<div class="buy-gem-total">
{{ $t('sendGiftTotal') }}
</div>
<!-- the actual dollar amount -->
<div class="buy-gem-amount">
<span>
{{ formatter.format(totalGems) }}
</span>
</div>
<!-- change to sending own gems page -->
<div
:class="{active: selectedPage === 'ownGems'}"
class="gem-state-change"
@click="selectPage('ownGems')"
>
{{ $t('wantToSendOwnGems') }}
</div>
</div>
<!-- paying for gems -->
<payments-buttons
class="payment-buttons"
:stripe-fn="() => redirectToStripe({gift, uuid: userReceivingGift._id, receiverName})"
:paypal-fn="() => openPaypalGift({
gift: gift, giftedTo: userReceivingGift._id, receiverName,
})"
:amazon-data="{type: 'single', gift, giftedTo: userReceivingGift._id, receiverName}"
/>
</div>
</div>
<!-- send gems from balance -->
<div
v-show="selectedPage === 'ownGems'"
>
<div class="gem-group">
<label v-once>
{{ $t('howManyGemsSend') }}
</label>
<div class="d-flex align-items-center justify-content-center">
<div
class="gray-circle"
@click="gift.gems.amount <= 0
? gift.gems.amount = 0
: gift.gems.amount--"
>
<div
class="icon-negative"
v-html="icons.negativeIcon"
></div>
</div>
<div class="input-group">
<div class="input-group-prepend input-group-icon align-items-center">
<div
class="icon-gem"
v-html="icons.gemIcon"
></div>
</div>
<input
id="gemsForm"
v-model="gift.gems.amount"
class="form-control"
:max="maxGems"
>
</div>
<div
class="gray-circle"
@click="gift.gems.amount < maxGems
? gift.gems.amount++
: gift.gems.amount = maxGems"
>
<div
class="icon-positive"
v-html="icons.positiveIcon"
></div>
</div>
</div>
<div class="align-items-middle">
<div class="d-flex justify-content-center align-items-middle">
<span class="balance-text">
{{ $t('yourBalance') }}
</span>
<span
class="icon-gem balance-gem-margin"
style="display: inline-block;"
v-html="icons.gemIcon"
></span>
<span
class="balance-gems"
>
{{ maxGems }}
</span>
</div>
</div>
<div class="d-flex flex-column justify-content-center align-items-middle mt-3">
<button
v-if="fromBal"
class="btn btn-primary mx-auto mt-2"
type="submit"
:disabled="sendingInProgress"
@click="sendGift()"
>
{{ $t("send") }}
</button>
</div>
<!-- change to buying gems page -->
<div
:class="{active: selectedPage === 'buyGems'}"
class="gem-state-change"
@click="selectPage('buyGems')"
>
{{ $t('needToPurchaseGems') }}
</div>
</div>
</div>
</b-modal>
</template>
<style lang="scss">
@import '~@/assets/scss/mixins.scss';
#send-gift {
.modal-dialog {
max-width: 448px;
}
.modal-content {
width: 448px;
border-radius: 8px;
box-shadow: 0 14px 28px 0 rgba(26, 24, 29, 0.24), 0 10px 10px 0 rgba(26, 24, 29, 0.28);
}
.modal-body{
padding: 0px;
}
.modal-close {
position: absolute;
right: 16px;
top: 16px;
cursor: pointer;
.icon-close {
width: 18px;
height: 18px;
vertical-align: middle;
& ::v-deep svg path {
fill: #878190;
}
& :hover {
fill: #686274;
}
}
}
#subscription-form .subscribe-option {
background: #F9F9F9;
}
#subscription-form .selected {
background: rgba(213, 200, 255, 0.32);
// using rgba for transparency
}
}
</style>
<style scoped lang="scss">
@import '~@/assets/scss/colors.scss';
h2 {
color: $purple-300;
padding-top: 2rem;
}
.avatar-spacer {
height: 9px;
}
.display-name {
font-size: 0.875rem;
font-weight: bold;
line-height: 1.71;
margin: 0px 6px 0 20px;
}
.display-name a:hover{
text-decoration: none;
}
.user-name {
font-size: 0.75rem;
line-height: 1.33;
text-align: center;
color: $gray-100;
padding-bottom: 16px;
}
.row {
background-color: $gray-700;
margin: 0 0 0 0;
min-height: 32px;
}
.nav {
font-weight: bold;
font-size: 0.75rem;
min-height: 32px;
padding: 16px 0 0 0;
justify-content: center;
}
.nav-link {
color: $gray-100;
display: inline-block;
padding: 0px 8px 6px 8px;
&.active {
color: $purple-300;
border-bottom: 2px solid $purple-400;
}
&:hover {
color: $purple-300;
border-bottom: 2px solid $purple-400;
cursor: pointer;
}
}
.gem-group {
padding: 0 0 24px 0;
background-color: $gray-700;
margin: 0 0 0 0;
border-bottom-right-radius: 8px;
border-bottom-left-radius: 8px
}
label {
color: $gray-50;
font-size: 0.875rem;
font-weight: bold;
line-height: 1.71;
margin: 12px 0 16px 0;
width: 100%;
text-align: center;
}
.input-group {
width: 94px;
height: 32px;
margin: 0px 16px 0px 16px;
padding: 0;
border-radius: 2px;
border: solid 1px $gray-400;
background-color: $white;
}
.gray-circle {
border-radius: 100%;
border: solid 2px $gray-300;
width: 32px;
height: 32px;
cursor: pointer;
&:hover {
border-color: $purple-400;
}
}
.gray-circle:hover{
.icon-positive, .icon-negative {
& ::v-deep svg path {
fill: $purple-400;
}
}
}
.icon-gem {
width: 16px;
height: 16px;
margin-bottom: 4px;
}
.icon-positive, .icon-negative {
width: 10px;
height: 10px;
margin: 4px auto;
& ::v-deep svg path {
fill: $gray-300;
}
}
.buy-gem-total {
font-size: 0.875rem;
font-weight: bold;
line-height: 1.71;
padding-top: 24px;
text-align: center;
height: 28px;
}
.buy-gem-amount {
font-size: 1.25rem;
font-weight: bold;
line-height: 1.4;
margin: 16px 0 24px 0;
text-align: center;
height: 28px;
color: $green-10;
}
.balance-text {
font-size: 0.75rem;
font-weight: bold;
color: $gray-100;
line-height: 1.33;
margin: 12px 0px 0px 70px;
}
.balance-gem-margin {
margin: 8px 4px 0px 8px;
}
.balance-gems {
font-size: 0.75rem;
color: $gray-100;
line-height: 1.33;
margin: 12px 71px 0px 4px;
}
.gem-state-change {
color: $blue-10;
font-size: 0.875rem;
min-height: 24px;
margin: 16px 0 0;
text-align: center;
cursor: pointer;
}
.subscribe-option {
border-bottom-left-radius: 8px;
border-bottom-right-radius: 8px;
padding-bottom: 24px;
}
.payment-buttons {
padding: 24px 0;
}
</style>
<script>
// libs imports
import { mapState } from '@/libs/store';
// mixins imports
import paymentsMixin from '../../mixins/payments';
// component imports
import avatar from '../avatar';
import userLink from '../userLink';
import subscriptionOptions from '../settings/subscriptionOptions.vue';
import paymentsButtons from '@/components/payments/buttons/list';
// svg imports
import closeIcon from '@/assets/svg/close.svg';
import gemIcon from '@/assets/svg/gem.svg';
import positiveIcon from '@/assets/svg/positive.svg';
import negativeIcon from '@/assets/svg/negative.svg';
export default {
components: {
avatar,
subscriptionOptions,
paymentsButtons,
userLink,
},
mixins: [
paymentsMixin,
],
data () {
return {
subscription: {
key: '',
},
icons: Object.freeze({
closeIcon,
gemIcon,
positiveIcon,
negativeIcon,
}),
userReceivingGift: {
profile: '',
},
name: '',
display: '',
selectedPage: 'subscription',
gift: {
type: 'gems',
gems: {
amount: 0,
fromBalance: true,
},
},
sendingInProgress: false,
amazonPayments: {},
gemCost: 1,
};
},
computed: {
...mapState({
userLoggedIn: 'user.data',
}),
userName () {
const userName = this.userReceivingGift.auth
&& this.userReceivingGift.auth.local
&& this.userReceivingGift.auth.local.username;
return userName;
},
displayName () {
const displayName = this.userReceivingGift.profile.name;
return displayName;
},
userBacker () {
const userBacker = this.userReceivingGift.backer;
return userBacker;
},
userContributor () {
const userContributor = this.userReceivingGift.contributor;
return userContributor;
},
tierIcon () {
if (this.isNPC) {
return this.icons.tierNPC;
}
return this.icons[`tier${this.level}`];
},
fromBal () {
return this.gift.type === 'gems' && this.gift.gems.fromBalance;
},
maxGems () {
const maxGems = this.fromBal ? this.userLoggedIn.balance * 4 : 9999;
return maxGems;
},
formatter () {
const formatter = new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'USD',
minimumFractionDigits: 2,
});
return formatter;
},
totalGems () {
const totalGems = this.gift.gems.amount * 0.25;
return totalGems;
},
receiverName () {
if (
this.userReceivingGift.auth
&& this.userReceivingGift.auth.local
&& this.userReceivingGift.auth.local.username
) {
return this.userReceivingGift.auth.local.username;
}
return this.userReceivingGift.profile.name;
},
},
watch: {
startingPage () {
this.selectedPage = this.startingPage;
},
},
mounted () {
this.$root.$on('habitica::send-gift', data => {
this.userReceivingGift = data;
if (this.$store.state.giftModalOptions.startingPage) {
this.selectedPage = this.$store.state.giftModalOptions.startingPage;
this.$store.state.giftModalOptions.startingPage = '';
this.selectPage(this.selectedPage);
} else {
this.selectPage(this.startingPage);
}
this.setGemDefaults();
this.$root.$emit('bv::show::modal', 'send-gift');
});
},
methods: {
close () {
this.$root.$emit('bv::hide::modal', 'send-gift');
},
setGemDefaults () {
if (this.selectedPage === 'buyGems') {
this.gift.gems.amount = 20;
} else if (this.selectedPage === 'ownGems') {
this.gift.gems.amount = 1;
} else {
this.gift.gems.amount = 0;
}
},
selectPage (page) {
if (page === this.selectedPage) return;
if (page === 'buyGems') this.selectedPage = 'buyGems';
if (page === 'buyGems' && this.selectedPage === 'ownGems') return;
this.selectedPage = page || 'subscription';
this.setGemDefaults();
},
async sendGift () {
this.sendingInProgress = true;
await this.$store.dispatch('members:transferGems', {
toUserId: this.userReceivingGift._id,
gemAmount: this.gift.gems.amount,
});
this.close();
setTimeout(() => { // wait for the send gem modal to be closed
this.$root.$emit('habitica:payment-success', {
paymentMethod: 'balance',
paymentCompleted: true,
paymentType: 'gift-gems-balance',
gift: {
gems: {
amount: this.gift.gems.amount,
},
},
giftReceiver: this.receiverName,
});
}, 500);
},
onHide () {
this.sendingInProgress = false;
},
},
};
</script>

View File

@@ -739,6 +739,14 @@ export default {
} else if (attribute === 'email') {
this.user.auth.local.email = updates.newEmail;
window.alert(this.$t('emailSuccess')); // eslint-disable-line no-alert
} else if (attribute === 'password') {
this.passwordUpdates = {};
this.$store.dispatch('snackbars:add', {
title: 'Habitica',
text: this.$t('passwordSuccess'),
type: 'success',
timeout: true,
});
}
},
async changeDisplayName (newName) {

View File

@@ -450,10 +450,6 @@
background-color: $white;
}
.subscribe-option {
border-bottom: 1px solid $gray-600;
}
.svg-amazon-pay {
width: 208px;
}

View File

@@ -10,10 +10,17 @@
:value="block.key"
class="subscribe-option pt-2 pl-5 pb-3 mb-0"
:class="{selected: subscription.key === block.key}"
@click.native="subscription.key = block.key"
@click.native="updateSubscriptionData(block.key)"
>
<!-- eslint-enable vue/no-use-v-if-with-v-for -->
<div
v-if="userReceivingGift && userReceivingGift._id"
class="subscription-text ml-2 mb-1"
v-html="$t('giftSubscriptionRateText', {price: block.price, months: block.months})"
>
</div>
<div
v-else
class="subscription-text ml-2 mb-1"
v-html="$t('subscriptionRateText', {price: block.price, months: block.months})"
>
@@ -25,7 +32,18 @@
</div>
</b-form-radio>
</b-form-group>
<!-- payment buttons first is for gift subs and the second is for renewing subs -->
<payments-buttons
v-if="userReceivingGift && userReceivingGift._id"
:disabled="!subscription.key"
:stripe-fn="() => redirectToStripe({gift, uuid: userReceivingGift._id, receiverName})"
:paypal-fn="() => openPaypalGift({
gift: gift, giftedTo: userReceivingGift._id, receiverName,
})"
:amazon-data="{type: 'single', gift, giftedTo: userReceivingGift._id, receiverName}"
/>
<payments-buttons
v-else
:disabled="!subscription.key"
:stripe-fn="() => redirectToStripe({
subscription: subscription.key,
@@ -43,6 +61,7 @@
<style lang="scss">
@import '~@/assets/scss/colors.scss';
#subscription-form {
.custom-control .custom-control-label::before,
.custom-radio .custom-control-input:checked ~ .custom-control-label::after {
@@ -101,11 +120,22 @@ export default {
mixins: [
paymentsMixin,
],
props: {
userReceivingGift: {
type: Object,
default () {},
},
},
data () {
return {
subscription: {
key: null,
key: 'basic_earned',
},
gift: {
type: 'subscription',
subscription: { key: 'basic_earned' },
},
receiverName: '',
};
},
computed: {
@@ -114,7 +144,6 @@ export default {
},
subscriptionBlocksOrdered () {
const subscriptions = filter(subscriptionBlocks, o => o.discount !== true);
return sortBy(subscriptions, [o => o.months]);
},
},
@@ -131,6 +160,10 @@ export default {
return '<span class="subscription-bubble px-2 py-1">Gem cap at 25</span>';
}
},
updateSubscriptionData (key) {
this.subscription.key = key;
if (this.userReceivingGift._id) this.gift.subscription.key = key;
},
},
};
</script>

View File

@@ -209,6 +209,7 @@
<li>Fox_town</li>
<li>MaybeSteveRogers</li>
<li>shanaqui</li>
<li>deilann (not yet pictured)</li>
</ul>
</div>
</div>
@@ -218,7 +219,7 @@
{{ $t('commGuidePara014') }}<br>
<em>
Lemoness, lefnire, Slappybag, litenull, Shaner, Bobbyroberts99, wc8,
deilann, Breadstrings, Megan, Blade, and Daniel the Bard
Breadstrings, Megan, Blade, and Daniel the Bard
</em>
</p>
<h2 id="final">

View File

@@ -662,6 +662,11 @@
margin-bottom: 0;
}
.custom-control-input {
z-index: -1;
opacity: 0;
}
.modal-header {
.form-group {
margin-bottom: 1rem;

View File

@@ -126,7 +126,7 @@
</div>
</div>
<div class="row">
<div class="col-12 col-md-6 offset-md-3 text-center nav">
<div class="text-center nav">
<div
class="nav-item"
:class="{active: selectedPage === 'profile'}"
@@ -470,6 +470,7 @@
.gift-icon svg {
height: 14px;
}
</style>
<style lang="scss" scoped>
@@ -538,6 +539,7 @@
}
.nav {
width: 100%;
font-weight: bold;
min-height: 40px;
justify-content: center;
@@ -710,6 +712,27 @@
}
}
}
@media (max-width: 990px) {
.profile-actions {
flex-direction: column;
}
.profile-actions :not(:last-child) {
margin-bottom: 15px;
}
.profile-actions {
margin-right: 0;
}
}
@media (max-width: 550px) {
.member-details {
flex-direction: column;
}
.member-details .avatar {
margin-bottom: 15px;
}
}
</style>
<script>
@@ -969,7 +992,8 @@ export default {
axios.post(`/api/v4/user/block/${this.user._id}`);
},
openSendGemsModal () {
this.$root.$emit('habitica::send-gems', this.user);
this.$store.state.giftModalOptions.startingPage = 'buyGems';
this.$root.$emit('habitica::send-gift', this.user);
},
adminTurnOnShadowMuting () {
if (!this.hero.flags) {

View File

@@ -4,7 +4,7 @@
class="standard-page"
>
<div class="row">
<div class="col-12 col-md-6">
<div class="stats-section-equipment col-12 col-md-6">
<h2 class="text-center">
{{ $t('equipment') }}
</h2>
@@ -12,7 +12,7 @@
<div
v-for="(label, key) in equipTypes"
:key="key"
class="col-12 col-md-4 item-wrapper"
class="item-wrapper"
>
<div
v-if="label !== 'skip'"
@@ -48,7 +48,7 @@
</div>
</div>
</div>
<div class="col-12 col-md-6">
<div class="stats-section-costume col-12 col-md-6">
<h2 class="text-center">
{{ $t('costume') }}
</h2>
@@ -57,7 +57,7 @@
<div
v-for="(label, key) in equipTypes"
:key="key"
class="col-12 col-md-4 item-wrapper"
class="item-wrapper"
>
<!-- Append a "C" to the key name since HTML IDs have to be unique.-->
<div
@@ -111,7 +111,7 @@
</div>
</div>
<div class="row pet-mount-row">
<div class="col-12 col-md-6">
<div class="stats-section-pets col-12 col-md-6">
<h2
v-once
class="text-center"
@@ -119,8 +119,7 @@
{{ $t('pets') }}
</h2>
<div class="well pet-mount-well">
<div class="row col-12">
<div class="col-12 col-md-4">
<div class="pet-mount-well-image">
<div
class="box"
:class="{white: user.items.currentPet}"
@@ -131,7 +130,7 @@
></div>
</div>
</div>
<div class="col-12 col-md-8">
<div class="pet-mount-well-text">
<div>{{ formatAnimal(user.items.currentPet, 'pet') }}</div>
<div>
<strong>{{ $t('petsFound') }}:</strong>
@@ -142,10 +141,9 @@
{{ beastMasterProgress(user.items.pets) }}
</div>
</div>
</div>
</div>
</div>
<div class="col-12 col-md-6">
<div class="stats-section-mounts col-12 col-md-6">
<h2
v-once
class="text-center"
@@ -153,28 +151,26 @@
{{ $t('mounts') }}
</h2>
<div class="well pet-mount-well">
<div class="row col-12">
<div class="col-12 col-md-4">
<div class="pet-mount-well-image">
<div
class="box"
:class="{white: user.items.currentMount}"
>
<div
class="box"
:class="{white: user.items.currentMount}"
>
<div
class="mount"
:class="`Mount_Icon_${user.items.currentMount}`"
></div>
</div>
class="mount"
:class="`Mount_Icon_${user.items.currentMount}`"
></div>
</div>
<div class="col-12 col-md-8">
<div>{{ formatAnimal(user.items.currentMount, 'mount') }}</div>
<div>
<strong>{{ $t('mountsTamed') }}:</strong>
<span>{{ totalCount(user.items.mounts) }}</span>
</div>
<div>
<strong>{{ $t('mountMasterProgress') }}:</strong>
<span>{{ mountMasterProgress(user.items.mounts) }}</span>
</div>
</div>
<div class="pet-mount-well-text">
<div>{{ formatAnimal(user.items.currentMount, 'mount') }}</div>
<div>
<strong>{{ $t('mountsTamed') }}:</strong>
<span>{{ totalCount(user.items.mounts) }}</span>
</div>
<div>
<strong>{{ $t('mountMasterProgress') }}:</strong>
<span>{{ mountMasterProgress(user.items.mounts) }}</span>
</div>
</div>
</div>
@@ -309,15 +305,13 @@
v-if="showStatsSave"
class="row save-row"
>
<div class="col-12 col-md-6 offset-md-3 text-center">
<button
class="btn btn-primary"
:disabled="loading"
@click="saveAttributes()"
>
{{ loading ? $t('loading') : $t('save') }}
</button>
</div>
<button
class="btn btn-primary"
:disabled="loading"
@click="saveAttributes()"
>
{{ loading ? $t('loading') : $t('save') }}
</button>
</div>
</div>
</div>
@@ -650,10 +644,17 @@ export default {
border-radius: 2px;
padding: 0.4em;
padding-top: 1em;
display: flex;
justify-content: center;
flex-wrap: wrap;
gap: 15px;
}
.well.pet-mount-well {
padding-left: 15px;
padding-bottom: 1em;
flex-wrap: nowrap;
justify-content: flex-start;
strong {
margin-right: .2em;
@@ -690,12 +691,13 @@ export default {
}
.save-row {
margin-top: 1em;
margin: 2em 0 1em 0;
justify-content: center;
}
.gear.box {
vertical-align: top;
margin: 0 auto;
// margin: 0 auto;
}
.gear-label {
@@ -721,4 +723,34 @@ export default {
// breaks the long words without a space
word-break: break-word;
}
@media (max-width: 850px) {
#stats .col-md-6 {
flex: none;
max-width: 100%;
}
}
@media(max-width: 990px) {
.modal-body #stats .col-md-6 {
flex: none;
max-width: 100%;
}
[class^="stats-section-"] {
margin-bottom: 30px;
}
#allocation {
.box {
width: 100%;
height: 100%;
.col-9 {
padding: 0;
margin: 0;
}
.col-9 div:first-child {
font-size: 13px;
}
}
}
}
</style>

View File

@@ -39,6 +39,11 @@ export default [
type: 'Moderator',
uuid: '28771972-ca6d-4c03-8261-e1734aa7d21d',
},
{
name: 'deilann',
type: 'Moderator',
uuid: 'e7b5d1e2-3b6e-4192-b867-8bafdb03eeec',
},
{
name: 'Dewines',
type: 'Moderator',

View File

@@ -124,6 +124,9 @@ export default function () {
profileOptions: {
startingPage: '',
},
giftModalOptions: {
startingPage: '',
},
rageModalOptions: {
npc: '',
},

View File

@@ -0,0 +1 @@
{}

View File

@@ -0,0 +1 @@
{}

View File

@@ -0,0 +1 @@
{}

View File

@@ -0,0 +1 @@
{}

View File

@@ -0,0 +1,3 @@
{
}

View File

@@ -2476,7 +2476,7 @@
"armorSpecialFall2021MageNotes": "Kragen mit vielen spitzen Spitzen sind besonders Beliebt bei Basisbösewichten. Erhöht Intelligenz um <%= int %>. Limitierte Ausgabe 2021 Herbstausrüstung.",
"armorSpecialFall2021HealerText": "Roben des Erweckens",
"armorSpecialFall2021HealerNotes": "Hergestellt aus flammen-resistentem Material sind diese Roben besonders geeignet um heilende Flammen und reinige Feuer anzuwenden. Erhöht Ausdauer um <%= con %>. Limitierte Ausgabe 2021 Herbstausrüstung.",
"armorArmoireBagpipersKiltNotes": "Ein robuster, langlebiger Kilt wird Dir gute Dienste erweisen. Erhöht Ausdauer um <%= con %>. Dudelsackpfeiferset (Gegenstand 2 von 3).",
"armorArmoireBagpipersKiltNotes": "Ein robuster, langlebiger Kilt wird Dir gute Dienste erweisen. Erhöht Ausdauer um <%= con %>. Verzauberter Schrank: Dudelsackpfeiferset (Gegenstand 2 von 3).",
"armorArmoireHeraldsTunicText": "Tunika des Herolds",
"armorArmoireSoftBlackSuitText": "Weicher Schwarzer Anzug",
"headSpecialFall2021RogueNotes": "Tja, Du steckst fest. Jetzt bist Du dazu verdonnert alte Verliese heimzusuchen und allerlei Unrat mit dir aufzusammeln. Ohweh! Erhöht Wahrnehmung um <%= per %>. Limitierte Ausgabe 2021 Herbstausrüstung.",
@@ -2489,7 +2489,7 @@
"armorArmoireSoftBlackSuitNotes": "Schwarz ist eine mysteriöse Farbe. Mit Sicherheit inspiriert es zu den interessantesten Träumen. Erhöht Konstitution und Wahrnehmung um jeweils <%=attrs %>. Verzauberter Schrank: Schwarzes Wohlfühl-Set (Gegenstand 2 von 3).",
"headSpecialFall2021HealerNotes": "Deine eigene Magie lässt deine Haare zu schockierenden, hellen Flammen werden, wenn du diese Maske aufsetzt. Erhöht Intelligenz um <%= int %>. Limitierte Ausgabe 2021 Herbstausrüstung.",
"weaponArmoireSkullLanternText": "Totenkopflaterne",
"weaponArmoireSkullLanternNotes": "Lasse ihr Leuchten deinen Weg durch die tiefste Finsternis erhellen. Erhöht Intelligenz um <%= int %>. Verzauberter Schrank:Unabhängiger Gegenstand.",
"weaponArmoireSkullLanternNotes": "Lasse ihr Leuchten deinen Weg durch die tiefste Finsternis erhellen. Erhöht Intelligenz um <%= int %>. Verzauberter Schrank: Unabhängiger Gegenstand.",
"offHandCapitalized": "Schildhand-Gegenstand",
"armorMystery202112Text": "Antarktischer Nixenschwanz",
"armorMystery202112Notes": "Gleite mit diesem schimmerden Schwanz durch eisige Gewässser ohne jegliche Kälte zu spühren. Gewährt keinen Attributbonus. Dezember 2021 Abonnentengegenstand.",
@@ -2625,7 +2625,7 @@
"weaponArmoireHuntingHornNotes": "Tuuut! Tuut! Tuut! Rufe deine Party für ein Abenteuer oder eine Quest zusammen, indem Du auf diesem Horn spielst. Erhöht Stärke um <%= str %> und Intelligenz um <%= int %>. Verzauberter Schrank: Musikinstrument Set 1 (Gegenstand 1 von 3)",
"headArmoireStrawRainHatText": "Stroh-Regenhut",
"shieldArmoireSnareDrumText": "Kleine Trommel",
"shieldArmoireSnareDrumNotes": "Rat-a-tat-ta! Rufe Deine Party für eine Parade oder einen Marsch zusammen, indem Du auf dieser Trommel spielst. Erhöht Ausdauer um <%= con %> und Intelligenz um <%= int %>. Musikinstrument Set 1 (Gegenstand 3 von 3)",
"shieldArmoireSnareDrumNotes": "Rat-a-tat-ta! Rufe Deine Party für eine Parade oder einen Marsch zusammen, indem Du auf dieser Trommel spielst. Erhöht Ausdauer um <%= con %> und Intelligenz um <%= int %>. Verzauberter Schrank: Musikinstrument Set 1 (Gegenstand 3 von 3)",
"shieldArmoireSpanishGuitarNotes": "Kling! Kling! Klooong! Rufe Deine Party für ein Konzert oder eine Feierlichkeit zusammen, indem Du auf dieser Gitarre spielst. Erhöht Wahrnehmung um <%= per %> und Intelligenz um <%= int %>. Verzauberter Schrank: Musikinstrument Set 1 (Gegenstand 2 von 3)",
"shieldArmoireSpanishGuitarText": "Spanische Gitarre",
"armorArmoireStrawRaincoatNotes": "Dieser gewebte Strohumhang wird Dich während Deiner Quest trocken halten und Deine Rüstung vor dem Rosten bewahren. Wage Dich jedoch nicht zu nah an Kerzen heran. Erhöht Ausdauer um <%= con %>. Verzauberter Schrank: Stroh Regenmantel Set (Gegenstand 1 von 2).",
@@ -2634,13 +2634,13 @@
"backMystery202206Notes": "Wunderliche Flügel aus Wasser und Wellen! Verleiht keinen Vorteil. Juni 2022 Abonnentengegenstand.",
"headMystery202206Notes": "Die blaue Perle in diesem Diadem verleiht dir Wasserbändigungskräfte. Nutze sie weise! Verleiht keinen Vorteil. Juni 2022 Abonnentengegenstand.",
"weaponArmoireBlueKiteText": "Blauer Drachen",
"weaponArmoireBlueKiteNotes": "Hoch am Himmel fliegt der Drachen, welche Stunts kann er wohl machen? Erhöht alle Werte um jeweils <%= attrs %> . Verzauberter Kleiderschrank: Drachen Set (Gegenstand 1 von 5)",
"weaponArmoireBlueKiteNotes": "Hoch am Himmel fliegt der Drachen, welche Stunts kann er wohl machen? Erhöht alle Werte um jeweils <%= attrs %> . Verzauberter Schrank: Drachen Set (Gegenstand 1 von 5)",
"weaponArmoireGreenKiteText": "Grüner Drachen",
"weaponArmoireGreenKiteNotes": "Einen schöneren Drachen findet man kaum, in grün und gelb, es ist ein Traum. Erhöht alle Werte um jeweils <%= attrs %> . Verzauberter Kleiderschrank: Drachen Set (Gegenstand 2 von 5)",
"weaponArmoireGreenKiteNotes": "Einen schöneren Drachen findet man kaum, in grün und gelb, es ist ein Traum. Erhöht alle Werte um jeweils <%= attrs %> . Verzauberter Schrank: Drachen Set (Gegenstand 2 von 5)",
"weaponArmoireOrangeKiteText": "Oranger Drachen",
"weaponArmoireOrangeKiteNotes": "Mit Farben wie der Aufgang und Untergang der Sonne, hoch zu fliegen ist für diesen Drachen eine Wonne. Erhöht alle Werte um jeweils <%= attrs %> . Verzauberter Kleiderschrank: Drachen Set (Gegenstand 3 von 5)",
"weaponArmoireOrangeKiteNotes": "Mit Farben wie der Aufgang und Untergang der Sonne, hoch zu fliegen ist für diesen Drachen eine Wonne. Erhöht alle Werte um jeweils <%= attrs %> . Verzauberter Schrank: Drachen Set (Gegenstand 3 von 5)",
"weaponArmoirePinkKiteText": "Pinker Drachen",
"weaponArmoirePinkKiteNotes": "Er steigt auf , schießt zu Boden, dreht sich flink, dein Drachen im leuchtenden Pink. Erhöht alle Werte um jeweils <%= attrs %> . Verzauberter Kleiderschrank: Drachen Set (Gegenstand 4 von 5)",
"weaponArmoirePinkKiteNotes": "Er steigt auf , schießt zu Boden, dreht sich flink, dein Drachen im leuchtenden Pink. Erhöht alle Werte um jeweils <%= attrs %> . Verzauberter Schrank: Drachen Set (Gegenstand 4 von 5)",
"weaponArmoireYellowKiteText": "Gelber Drachen",
"weaponArmoireYellowKiteNotes": "Er saust am Himmel hin und her, das fällt dem heiteren Drachen nicht schwer. Erhöht alle Werte um jeweils <%= attrs %> . Verzauberter Kleiderschrank: Drachen Set (Gegenstand 5 von 5)"
"weaponArmoireYellowKiteNotes": "Er saust am Himmel hin und her, das fällt dem heiteren Drachen nicht schwer. Erhöht alle Werte um jeweils <%= attrs %> . Verzauberter Schrank: Drachen Set (Gegenstand 5 von 5)"
}

View File

@@ -604,7 +604,7 @@
"cuddleBuddiesText": "\"Kuschelkumpel\" Quest-Paket",
"cuddleBuddiesNotes": "Beinhaltet 'Das Killerkaninchen', 'Das Ruchlose Frettchen' und 'Die Meerschweinchen Gang'. Verfügbar bis zum 31. März.",
"aquaticAmigosText": "\"Feuchte Freunde\" Quest-Paket",
"aquaticAmigosNotes": "Beinhaltet 'Der magische Axolotl', 'Der Kraken von Unfertik' und 'Der Ruf des Octothulu'. Verfügbar bis zum 31. August.",
"aquaticAmigosNotes": "Beinhaltet 'Der magische Axolotl', 'Der Kraken von Unfertik' und 'Der Ruf des Octothulu'. Verfügbar bis zum 30. Juni.",
"questSeaSerpentText": "Gefahr in der Tiefe: Seeschlangen-Angriff!",
"questSeaSerpentNotes": "Du fühlst Deine Glückssträhne - es ist die perfekte Zeit für einen Ausflug zur Seepferdchen-Rennstrecke. Du steigst in das U-Boot bei Diligent Docks ein und machst Dich bereit für die Reise nach Dilatory, aber kaum bist Du untergetaucht, erschüttert ein Aufprall das U-Boot und lässt seine Insassen stolpern. “Was ist los?” schreit @AriesFaries.<br><br>Du schaust durch ein nahegelegenes Bullauge und bist schockiert von der Wand aus schimmernden Schuppen, die an ihm vorbeizieht. “Seeschlange!” ruft Captain @Witticaster über die Gegensprechanlage aus. “Haltet euch fest, sie kommt schon wieder!” Während Du Dich an die Armlehnen Deines Sitzes klammerst, ziehen Deine unerledigten Aufgaben vor Deinen Augen vorüber. “Vielleicht, wenn wir zusammen arbeiten und sie erledigen”, denkst Du, “können wir dieses Monster vertreiben!”",
"questSeaSerpentCompletion": "Von Deiner Hingabe angeschlagen, flieht die Seeschlange und verschwindet in den Tiefen. Als Du in Dilatory ankommst, entfährt Dir ein Seufzer der Erleichterung, bevor Du bemerkst, dass @*~Seraphina~ sich mit drei durchsichtigen Eiern in ihren Armen nähert. “Hier, die hier sollst Du haben”, sagt sie. “Du weißt, wie man mit einer Seeschlange umgeht!” Als Du die Eier annimmst, gelobst Du von neuem, standhaft bei der Erfüllung Deiner Aufgaben zu bleiben, um sicherzustellen, dass es nicht zu einer Wiederholung kommt.",

View File

@@ -3,7 +3,7 @@
"step1": "Βήμα 1: Εισάγετε Αποστολές",
"webStep1Text": "Το Habitica δεν είναι τίποτα χωρίς στόχους στον πραγματικό κόσμο, οπότε θέσε μερικούς. Μπορείς να προσθέσεις περισσότερους αργότερα! Οι στόχοι μπορούν να προστεθούν πατώντας το πράσινο κουμπί \"Δημιουργία\".\n* **Ρύθμισε τις [Υποχρεώσεις σου](http://habitica.wikia.com/wiki/To-Dos):** Βάλε στόχους που θέλεις να υλοποιείς σπάνια ή μια μόνο φορά στη στήλη των Υποχρεώσεων, έναν κάθε φορά. Μπορείς να τροποποιήσεις τους στόχους κάνοντας κλικ πάνω τους και να προσθέσεις λίστες, ημερομηνίες και άλλα!\n* **Ρύθμισε τους [Καθημερινούς Στόχους](http://habitica.wikia.com/wiki/Dailies):** Πρόσθεσε δραστηριότητες που πρέπει να κάνεις καθημερινά, ή μια συγκεκριμένη μέρα της εβδομάδας, μήνα ή του χρόνου στη στήλη με τις Καθημερινές Υποχρεώσεις. Κάνε κλικ σε έναν στόχο για να τροποποιήσεις το πότε πρέπει να τον ολοκληρώσεις, ή να ορίσεις μια ημερομηνία εκκίνησης. Μπορείς επίσης να ορίσεις μια ημερομηνία ολοκλήρωσης σε επαναλαμβανόμενη βάση, για παράδειγμα, κάθε 3 μέρες.\n* **Ρύθμισε τις [Συνήθειες](http://habitica.wikia.com/wiki/Habits):** Πρόσθεσε Συνήθειες που θέλεις να υιοθετήσεις στη στήλη των Συνηθειών. Μπορείς να τροποποιήσεις μια Συνήθεια ώστε να την θέσεις ως καλή :heavy_plus_sign: η κακή συνήθεια :heavy_minus_sign:\n* **Ρύθμισε τις [Ανταμοιβές](http://habitica.wikia.com/wiki/Rewards):** Επιπλέον από τις Ανταμοιβές που υπάρχουν μέσα στην εφαρμογή, πρόσθεσε δραστηριότητες ή κεράσματα τα οποία θέλεις να χρησιμοποιήσεις ως κίνητρο στην στήλη των Ανταμοιβών. Είναι σημαντικό να κάνεις ένα διάλειμμα ή να επιτρέπεις στον εαυτό σου λίγη ικανοποίηση με μέτρο!\n* Αν χρειάζεσαι έμπνευση για να προσθέσεις στόχους, μπορείς να κοιτάξεις στις σελίδες του wiki για τις [Παραδείγματα για Συνήθειες](http://habitica.wikia.com/wiki/Sample_Habits), [Παραδείγματα Καθημερινών Στόχων](http://habitica.wikia.com/wiki/Sample_Dailies), [Παραδείγματα Υποχρεώσεων](http://habitica.wikia.com/wiki/Sample_To-Dos), and [Παραδείγματα Ανταμειβών](http://habitica.wikia.com/wiki/Sample_Custom_Rewards).",
"step2": "Βήμα 2: Πάρτε Πόντους Κάνοντας Πράξεις στην Πραγματική Ζωή",
"webStep2Text": "Now, start tackling your goals from the list! As you complete tasks and check them off in Habitica, you will gain [Experience](http://habitica.wikia.com/wiki/Experience_Points), which helps you level up, and [Gold](http://habitica.wikia.com/wiki/Gold_Points), which allows you to purchase Rewards. If you fall into bad habits or miss your Dailies, you will lose [Health](http://habitica.wikia.com/wiki/Health_Points). In that way, the Habitica Experience and Health bars serve as a fun indicator of your progress toward your goals. You'll start seeing your real life improve as your character advances in the game.",
"webStep2Text": "Τώρα, ξεκίνα να κυνηγάς τους στόχους σου από τη λίστα! Όσο ολοκληρώνεις και τσεκάρεις στόχους στο Habitica, θα κερδίζεις [Πόντους Εμπειρίας](http://habitica.wikia.com/wiki/Experience_Points), πράγμα που θα σε βοηθήσει να ανεβαίνεις επίπεδα, και [Χρυσό](http://habitica.wikia.com/wiki/Gold_Points), που σου επιτρέπει να αγοράζεις Ανταμειβές. Αν επιστρέψεις σε κακές συνήθειες, ή αν αποτύχεις στους καθημερινούς στόχους σου, θα χάσεις [Ζωή](http://habitica.wikia.com/wiki/Health_Points). Με αυτόν τον τρόπο, η Εμπειρία Habitica και οι μπάρες Ζωής, λειτουργούν ως μια διασκεδαστική ένδειξη της προόδου σου προς τους στόχους σου. Θα αρχίσεις να βλέπεις την πραγματική σου ζωή να βελτιώνεται όσο ο χαρακτήρας σου προχωρά στο παιχνίδι.",
"step3": "Βήμα 3: Προσαρμόστε και Εξερευνήστε το Habitica",
"webStep3Text": "Once you're familiar with the basics, you can get even more out of Habitica with these nifty features:\n * Organize your tasks with [tags](http://habitica.wikia.com/wiki/Tags) (edit a task to add them).\n * Customize your [avatar](http://habitica.wikia.com/wiki/Avatar) by clicking the user icon in the upper-right corner.\n * Buy your [Equipment](http://habitica.wikia.com/wiki/Equipment) under Rewards or from the [Shops](<%= shopUrl %>), and change it under [Inventory > Equipment](<%= equipUrl %>).\n * Connect with other users via the [Tavern](http://habitica.wikia.com/wiki/Tavern).\n * Starting at Level 3, hatch [Pets](http://habitica.wikia.com/wiki/Pets) by collecting [eggs](http://habitica.wikia.com/wiki/Eggs) and [hatching potions](http://habitica.wikia.com/wiki/Hatching_Potions). [Feed](http://habitica.wikia.com/wiki/Food) them to create [Mounts](http://habitica.wikia.com/wiki/Mounts).\n * At level 10: Choose a particular [class](http://habitica.wikia.com/wiki/Class_System) and then use class-specific [skills](http://habitica.wikia.com/wiki/Skills) (levels 11 to 14).\n * Form a party with your friends (by clicking [Party](<%= partyUrl %>) in the navigation bar) to stay accountable and earn a Quest scroll.\n * Defeat monsters and collect objects on [quests](http://habitica.wikia.com/wiki/Quests) (you will be given a quest at level 15).",
"overviewQuestions": "Have questions? Check out the [FAQ](<%= faqUrl %>)! If your question isn't mentioned there, you can ask for further help in the [Habitica Help guild](<%= helpGuildUrl %>).\n\nGood luck with your tasks!"

View File

@@ -795,6 +795,14 @@
"backgroundSailboatAtSunsetText": "Sailboat At Sunset",
"backgroundSailboatAtSunsetNotes": "Enjoy the beauty of a sailboat at sunset.",
"backgrounds072022": "SET 98: Released July 2022",
"backgroundBioluminescentWavesText": "Bioluminescent Waves",
"backgroundBioluminescentWavesNotes": "Admire the glow of Bioluminescent Waves.",
"backgroundUnderwaterCaveText": "Underwater Cave",
"backgroundUnderwaterCaveNotes": "Explore an Underwater Cave.",
"backgroundUnderwaterStatuesText": "Underwater Statue Garden",
"backgroundUnderwaterStatuesNotes": "Try not to blink in an Underwater Statue Garden.",
"timeTravelBackgrounds": "Steampunk Backgrounds",
"backgroundAirshipText": "Airship",
"backgroundAirshipNotes": "Become a sky sailor on board your very own Airship.",

View File

@@ -428,7 +428,7 @@
"weaponSpecialSummer2022RogueText": "Crab Claw",
"weaponSpecialSummer2022RogueNotes": "If you're in a pinch, don't hesitate to show these fearsome claws! Increases Strength by <%= str %>. Limited Edition 2022 Summer Gear.",
"weaponSpecialSummer2022WarriorText": "Cyclone Shield",
"weaponSpecialSummer2022WarriorText": "Whirling Cyclone",
"weaponSpecialSummer2022WarriorNotes": "It spins! It redirects! And it brings the storm! Increases Strength by <%= str %>. Limited Edition 2022 Summer Gear.",
"weaponSpecialSummer2022MageText": "Manta Ray Staff",
"weaponSpecialSummer2022MageNotes": "Magically clear the waters ahead of you with one swirl of this staff. Increases Intelligence by <%= int %> and Perception by <%= per %>. Limited Edition 2022 Summer Gear.",
@@ -1073,7 +1073,7 @@
"armorSpecialSummer2022WarriorText": "Waterspout Armor",
"armorSpecialSummer2022WarriorNotes": "Get ready for a watery battle as you surround yourself with this twirling, whirling column of air and mist. Increases Constitution by <%= con %>. Limited Edition 2022 Summer Gear.",
"armorSpecialSummer2022MageText": "Manta Ray Armor",
"armorSpecialSummer2022MageNotes": "Keep your head protected as you dive into your tasks or into the deepest waters. Increases Intelligence by <%= int %>. Limited Edition 2022 Summer Gear.",
"armorSpecialSummer2022MageNotes": "When wearing this armor, you will glide easily through your work like the manta ray glides through water. Increases Intelligence by <%= int %>. Limited Edition 2022 Summer Gear.",
"armorSpecialSummer2022HealerText": "Angelfish Tail",
"armorSpecialSummer2022HealerNotes": "Use your colorful fins to scoot about the reef and help those in need of rest and healing. Increases Constitution by <%= con %>. Limited Edition 2022 Summer Gear.",
@@ -1185,6 +1185,8 @@
"armorMystery202112Notes": "Glide through icy seas and never get cold with this glimmering tail. Confers no benefit. December 2021 Subscriber Item.",
"armorMystery202204Text": "Virtual Adventurer Capsule",
"armorMystery202204Notes": "Looks like doing your tasks now requires pushing these mysterious buttons! What could they do? Confers no benefit. April 2022 Subscriber Item.",
"armorMystery202207Text": "Jammin' Jelly Armor",
"armorMystery202207Notes": "This armor will have you looking glamorous and gelatinous. Confers no benefit. July 2022 Subscriber Item.",
"armorMystery301404Text": "Steampunk Suit",
"armorMystery301404Notes": "Dapper and dashing, wot! Confers no benefit. February 3015 Subscriber Item.",
"armorMystery301703Text": "Steampunk Peacock Gown",
@@ -1360,6 +1362,8 @@
"armorArmoireGardenersOverallsNotes": "Dont be afraid to work down in the dirt when youre wearing these durable overalls. Increases Constitution by <%= con %>. Enchanted Armoire: Gardener Set (Item 1 of 4).",
"armorArmoireStrawRaincoatText": "Straw Raincoat",
"armorArmoireStrawRaincoatNotes": "This woven straw cape will keep you dry and your armor from rusting while on your quest. Just dont venture too near a candle! Increases Constitution by <%= con %>. Enchanted Armoire: Straw Raincoat Set (Item 1 of 2).",
"armorArmoireFancyPirateSuitText": "Fancy Pirate Jacket",
"armorArmoireFancyPirateSuitNotes": "Wear this fine jacket well as you organize your ships library or talk it through as a crew. Increases Constitution and Intelligence by <%= attrs %> each. Enchanted Armoire: Fancy Pirate Set (Item 1 of 3).",
"headgear": "helm",
"headgearCapitalized": "Headgear",
@@ -1750,7 +1754,7 @@
"headSpecialSummer2022RogueText": "Crab Helm",
"headSpecialSummer2022RogueNotes": "No time to be crabby, we're out here shellebrating the summer's hottest crustacean puns. Increases Perception by <%= per %>. Limited Edition 2022 Summer Gear.",
"headSpecialSummer2022WarriorText": "Waterspout Helm",
"headSpecialSummer2022WarriorNotes": "Channel the power of water as you center yourself in this this intense vortex. Increases Strength by <%= str %>. Limited Edition 2022 Summer Gear.",
"headSpecialSummer2022WarriorNotes": "Channel the power of water as you center yourself in this intense vortex. Increases Strength by <%= str %>. Limited Edition 2022 Summer Gear.",
"headSpecialSummer2022MageText": "Manta Ray Helm",
"headSpecialSummer2022MageNotes": "Keep your head protected as you dive into your tasks or into the deepest waters. Increases Perception by <%= per %>. Limited Edition 2022 Summer Gear.",
"headSpecialSummer2022HealerText": "Angelfish Ear Fins",
@@ -1918,6 +1922,11 @@
"headMystery202202Notes": "You gotta have blue hair! Confers no benefit. February 2022 Subscriber Item.",
"headMystery202206Text": "Sea Sprite Circlet",
"headMystery202206Notes": "The blue pearl in this circlet grants you waterbending powers. Use them wisely! Confers no benefit. June 2022 Subscriber Item.",
"headMystery202207Text": "Jammin' Jelly Helm",
"headMystery202207Notes": "Need a hand with your tasks? Will several dozen bioluminescent tentacles do? Confers no benefit. July 2022 Subscriber Item.",
"headMystery202208Text": "Perky Ponytail",
"headMystery202208Notes": "Enjoy showing off this voluminous hair - it can double as a whip in a pinch! Confers no benefit. August 2022 Subscriber Item.",
"headMystery301404Text": "Fancy Top Hat",
"headMystery301404Notes": "A fancy top hat for the finest of gentlefolk! January 3015 Subscriber Item. Confers no benefit.",
"headMystery301405Text": "Basic Top Hat",
@@ -2091,6 +2100,8 @@
"headArmoireGardenersSunHatNotes": "The bright light of the day star wont shine in your eyes when you wear this wide-brimmed hat. Increases Perception by <%= per %>. Enchanted Armoire: Gardener Set (Item 2 of 4).",
"headArmoireStrawRainHatText": "Straw Rain Hat",
"headArmoireStrawRainHatNotes": "Youll be able to spot every obstacle in your path when you wear this water-resistant, conical hat. Increases Perception by <%= per %>. Enchanted Armoire: Straw Raincoat Set (Item 2 of 2).",
"headArmoireFancyPirateHatText": "Fancy Pirate Hat",
"headArmoireFancyPirateHatNotes": "Be protected from the sun and any seagulls flying overhead as you drink tea on the deck of your ship. Increases Perception by <%= per %>. Enchanted Armoire: Fancy Pirate Set (Item 2 of 3).",
"offhand": "off-hand item",
"offHandCapitalized": "Off-Hand Item",
@@ -2323,7 +2334,7 @@
"shieldSpecialSpring2022HealerText": "Peridot Shield",
"shieldSpecialSpring2022HealerNotes": "Formed by molten rock of the upper mantle, this shield can withstand any hit that comes its way. Increases Constitution by <%= con %>. Limited Edition 2022 Spring Gear.",
"shieldSpecialSummer2022WarriorText": "Shark Blade",
"shieldSpecialSummer2022WarriorText": "Feisty Shark",
"shieldSpecialSummer2022WarriorNotes": "It snaps! It bites! And it never, ever stops! Increases Constitution by <%= con %>. Limited Edition 2022 Summer Gear.",
"shieldSpecialSummer2022HealerText": "Remedial Ripples",
"shieldSpecialSummer2022HealerNotes": "Send out restorative magic in gentle ripples through the reef. Increases Constitution by <%= con %>. Limited Edition 2022 Summer Gear.",
@@ -2477,6 +2488,8 @@
"shieldArmoireSpanishGuitarNotes": "Tink! Tink! Thrummm! Gather your party for a concert or celebration by playing this guitar. Increases Perception by <%= per %> and Intelligence by <%= int %>. Enchanted Armoire: Musical Instrument Set 1 (Item 2 of 3)",
"shieldArmoireSnareDrumText": "Snare Drum",
"shieldArmoireSnareDrumNotes": "Rat-a-tat-tat! Gather your party for a parade or march into battle by playing this drum. Increases Constitution by <%= con %> and Intelligence by <%= int %>. Enchanted Armoire: Musical Instrument Set 1 (Item 3 of 3)",
"shieldArmoireTreasureMapText": "Treasure Map",
"shieldArmoireTreasureMapNotes": "X marks the spot! You never know what youll find when you follow this handy map to fabled treasures: gold, jewels, relics, or perhaps a petrified orange? Increases Strength and Intelligence by <%= attrs %> each. Enchanted Armoire: Fancy Pirate Set (Item 3 of 3).",
"back": "Back Accessory",
"backBase0Text": "No Back Accessory",
@@ -2829,6 +2842,8 @@
"eyewearMystery202204ANotes": "What's your mood today? Express yourself with these fun screens. Confers no benefit. April 2022 Subscriber Item.",
"eyewearMystery202204BText": "Virtual Face",
"eyewearMystery202204BNotes": "What's your mood today? Express yourself with these fun screens. Confers no benefit. April 2022 Subscriber Item.",
"eyewearMystery202208Text": "Sparkly Eyes",
"eyewearMystery202208Notes": "Lull your enemies into a false sense of security with these terrifyingly cute peepers. Confers no benefit. August 2022 Subscriber Item.",
"eyewearMystery301404Text": "Eyewear Goggles",
"eyewearMystery301404Notes": "No eyewear could be fancier than a pair of goggles - except, perhaps, for a monocle. Confers no benefit. April 3015 Subscriber Item.",
"eyewearMystery301405Text": "Monocle",

View File

@@ -129,6 +129,7 @@
"sendGiftHeading": "Send Gift to <%= name %>",
"sendGiftGemsBalance": "From <%= number %> Gems",
"sendGiftCost": "Total: $<%= cost %> USD",
"sendGiftTotal": "Total:",
"sendGiftFromBalance": "From Balance",
"sendGiftPurchase": "Purchase",
"sendGiftMessagePlaceholder": "Personal message (optional)",
@@ -363,5 +364,6 @@
"managerNotes": "Manager's Notes",
"assignedDateOnly": "Assigned on <strong><%= date %></strong>",
"assignedDateAndUser": "Assigned by <strong>@<%- username %></strong> on <strong><%= date %></strong>",
"claimRewards": "Claim Rewards"
"claimRewards": "Claim Rewards",
"chatTemporarilyUnavailable": "Chat is temporarily unavailable. Please try again later."
}

View File

@@ -87,6 +87,7 @@
"passwordChangeSuccess": "Your password was successfully changed to the one you just chose. You can now use it to access your account.",
"displayNameSuccess": "Display name successfully changed",
"emailSuccess": "Email successfully changed",
"passwordSuccess": "Password successfully changed",
"detachSocial": "De-register <%= network %>",
"detachedSocial": "Successfully removed <%= network %> authentication from your account",
"addedLocalAuth": "Successfully added local authentication",
@@ -124,6 +125,7 @@
"unsubscribeAllPush": "Check to Unsubscribe from all Push Notifications",
"correctlyUnsubscribedEmailType": "Correctly unsubscribed from \"<%= emailType %>\" emails.",
"subscriptionRateText": "Recurring <strong>$<%= price %> USD</strong> every <strong><%= months %> months</strong>",
"giftSubscriptionRateText": "<strong>$<%= price %> USD</strong> for <strong><%= months %> months</strong>",
"benefits": "Benefits",
"coupon": "Coupon",
"couponText": "We sometimes have events and give out promo codes for special gear. (eg, those who stop by our Wondercon booth)",
@@ -203,11 +205,13 @@
"transaction_gift_send": "Gifted to",
"transaction_gift_receive": "Received from",
"transaction_create_challenge": "Created challenge",
"transaction_create_bank_challenge": "Created bank challenge",
"transaction_create_guild": "Created guild",
"transaction_change_class": "Changed class",
"transaction_rebirth": "Used Orb of Rebirth",
"transaction_release_pets": "Released pets",
"transaction_release_mounts": "Released mounts",
"transaction_reroll": "Used Fortify Potion",
"transaction_subscription_perks": "From subscription perk"
"transaction_subscription_perks": "From subscription perk",
"transaction_admin_update_balance": "Admin given"
}

View File

@@ -3,6 +3,10 @@
"subscriptions": "Subscriptions",
"viewSubscriptions": "View Subscriptions",
"sendGems": "Send Gems",
"howManyGemsPurchase": "How many Gems would you like to purchase?",
"howManyGemsSend":"How many Gems would you like to send?",
"needToPurchaseGems": "Need to purchase Gems as a gift?",
"wantToSendOwnGems": "Want to send your own Gems?",
"buyGemsGold": "Buy Gems with Gold",
"mustSubscribeToPurchaseGems": "Must subscribe to purchase gems with GP",
"reachedGoldToGemCapQuantity": "Your requested amount <%= quantity %> exceeds the amount you can buy for this month (<%= convCap %>). The full amount becomes available within the first three days of each month. Thanks for subscribing!",
@@ -135,6 +139,8 @@
"mysterySet202204": "Virtual Adventurer Set",
"mysterySet202205": "Dusk-Winged Dragon Set",
"mysterySet202206": "Sea Sprite Set",
"mysterySet202207": "Jammin' Jelly Set",
"mysterySet202208": "Perky Ponytail Set",
"mysterySet301404": "Steampunk Standard Set",
"mysterySet301405": "Steampunk Accessories Set",
"mysterySet301703": "Peacock Steampunk Set",
@@ -197,5 +203,6 @@
"needToUpdateCard": "Need to update your card?",
"readyToResubscribe": "Are you ready to resubscribe?",
"cancelYourSubscription": "Cancel your subscription?",
"cancelSubAlternatives": "If you're having technical problems or Habitica doesn't seem to be working out for you, please consider <a href='mailto:admin@habitica.com'>contacting us</a>. We want to help you get the most from Habitica."
"cancelSubAlternatives": "If you're having technical problems or Habitica doesn't seem to be working out for you, please consider <a href='mailto:admin@habitica.com'>contacting us</a>. We want to help you get the most from Habitica.",
"sendAGift": "Send Gift"
}

View File

@@ -105,19 +105,19 @@
"weaponSpecialRoguishRainbowMessageText": "Roguish Rainbow Message",
"weaponSpecialRoguishRainbowMessageNotes": "This sparkly envelope contains messages of encouragement from Habiticans, and a touch of magic to help speed your deliveries! Nagtataás ng Pandamá ng <%= per %>.",
"weaponSpecialSkeletonKeyText": "Skeleton Key",
"weaponSpecialSkeletonKeyNotes": "All the best Sneakthieves carry a key that can open any lock! Nagtataás ng Pangangatawán ng <%= con %>.",
"weaponSpecialSkeletonKeyNotes": "Lahát ng mga mahuhusay na Singitpuslít ay may daláng susì na maaaring magbukas ng anumáng <i>candado</i>! Nagtataás ng Pangangatawán ng <%= con %>.",
"weaponSpecialNomadsScimitarText": "Nomad's Scimitar",
"weaponSpecialNomadsScimitarNotes": "The curved blade of this Scimitar is perfect for attacking Tasks from the back of a mount! Nagtataás ng Katalinuhan ng <%= int %>.",
"weaponSpecialNomadsScimitarNotes": "Ang malantík na talim ng Simitar na itó ay napakainam gamiting panambáng ng mga Gawain mulá sa likurán ng sakáy-alagà! Nagtataás ng Katalinuhan ng <%= int %>.",
"weaponSpecialFencingFoilText": "Fencing Foil",
"weaponSpecialFencingFoilNotes": "Should anyone dare to impugn your honor, you'll be ready with this fine foil! Nagtataás ng Lakás ng <%= str %>.",
"weaponSpecialFencingFoilNotes": "Kung may sinumang maglalakás-loób na siraan ang iyóng karangalan, handáng-handá ka gamit ang kahanga-hangang pang-Eskrimang patalím na itó! Nagtataás ng Lakás ng <%= str %>.",
"weaponSpecialTachiText": "Tachi",
"weaponSpecialTachiNotes": "This light and curved sword will shred your tasks to ribbons! Nagtataás ng Lakás ng <%= str %>.",
"weaponSpecialTachiNotes": "Gugutay-gutayín ng magaán at malantík na patalím na itó ang iyong mga Gawain. Nagtataás ng Lakás ng <%= str %>.",
"weaponSpecialAetherCrystalsText": "Aether Crystals",
"weaponSpecialAetherCrystalsNotes": "These bracers and crystals once belonged to the Lost Masterclasser herself. Nagtataás ng Lahát ng mga Katangian ng <%= attrs %>.",
"weaponSpecialAetherCrystalsNotes": "Dating pagmamay-arì mismo ng Ligáw na Dalubhasà ang mga sapín at kristál na itó. Nagtataás ng Lahát ng mga Katangian ng <%= attrs %>.",
"weaponSpecialYetiText": "Yeti-Tamer Spear",
"weaponSpecialYetiNotes": "This spear allows its user to command any yeti. Nagtataás ng Lakás ng <%= str %>. Biláng na Limbág na Kasangkapan ng Taglamíg ng ng 2013-2014.",
"weaponSpecialYetiNotes": "Nagbibigay ang sibát na itó ng kakayahang mag-utos sa anumáng <i>yeti</i>. Nagtataás ng Lakás ng <%= str %>. Biláng na Limbág na Kasangkapan ng Taglamíg ng ng 2013-2014.",
"weaponSpecialSkiText": "Ski-sassin Pole",
"weaponSpecialSkiNotes": "A weapon capable of destroying hordes of enemies! It also helps the user make very nice parallel turns. Nagtataás ng Lakás ng <%= str %>. Biláng na Limbág na Kasangkapan ng Taglamíg ng ng 2013-2014.",
"weaponSpecialSkiNotes": "Isáng sandata na kayang pumuksâ ng mga kuyog ng kalaban! Nakakatulong rin itóng mapahusay ang paglikô sa yelo. Nagtataás ng Lakás ng <%= str %>. Biláng na Limbág na Kasangkapan ng Taglamíg ng ng 2013-2014.",
"weaponSpecialCandycaneText": "Candy Cane Staff",
"weaponSpecialCandycaneNotes": "A powerful mage's staff. Powerfully DELICIOUS, we mean! Nagtataás ng Katalinuhan ng <%= int %> at Pandamá ng <%= per %>. Biláng na Limbág na Kasangkapan ng Taglamíg ng ng 2013-2014.",
"weaponSpecialSnowflakeText": "Bastón ng Kristál na Niyebe",
@@ -1953,7 +1953,7 @@
"shieldArmoireBaseballGloveNotes": "Perfect for the big tournament, or a friendly game of catch between tasks. Nagtataás ng Lakás ng <%= str %>. Enchanted Armoire: Baseball Set (Item 4 of 4).",
"shieldArmoireMeatFoodNotes": "Sometimes a bit of protein is what you need to grow up big and strong. Some of your pets are more eager for it than others! Nagtataás ng Lakás ng <%= str %>. Enchanted Armoire: Pet Food Set (Item 5 of 10).",
"shieldArmoireBouncyBubblesNotes": "Complete your relaxing bath with these exuberant bubbles! Nagtataás ng Lakás ng <%= str %>. Enchanted Armoire: Bubble Bath Set (Item 4 of 4).",
"weaponSpecialKS2019Notes": "Curved as a gryphon's beak and talons, this ornate polearm reminds you to power through when the task ahead feels daunting. Nagtataás ng Lakás ng <%= str %>.",
"weaponSpecialKS2019Notes": "Kasimbalikô ng tukâ at kukó ng <i>gryphon</i>, nagpapaalala ang mapalamutíng sibát na itó na tiyagaín ang mga gawain kapág nakakapanghinang-loób ang mga itó. Nagtataás ng Lakás ng <%= str %>.",
"shieldArmoireStrawberryFoodNotes": "A delicious fresh strawberry to feed to your pets! Do you know which pets like strawberries best? Nagtataás ng Lakás ng <%= str %>. Enchanted Armoire: Pet Food Set (Item 1 of 10).",
"shieldArmoireBagpipesNotes": "The uncharitable might say you're planning to wake the dead with these bagpipes -- but you know you're just motivating your Party to success! Nagtataás ng Lakás ng <%= str %>. Enchanted Armoire: Bagpiper Set (Item 3 of 3).",
"shieldArmoireGardenersSpadeNotes": "Whether youre digging in the garden, searching for buried treasure, or creating a secret tunnel, this trusty spade is at your side. Nagtataás ng Lakás ng <%= str %>. Enchanted Armoire: Gardener Set (Item 3 of 4).",

View File

@@ -604,7 +604,7 @@
"cuddleBuddiesText": "Lot de quêtes des acolytes à câlins",
"cuddleBuddiesNotes": "Contient \"Le lapin tueur\", \"L'abominable furet\", et \"Le gang des cochons d'Inde\". Disponible jusqu'au 31 mars.",
"aquaticAmigosText": "Lot de quêtes des amis aquatiques",
"aquaticAmigosNotes": "Contient “Laxototl magique”, “Le kraken dInkomplet”, et “Lappel dOctothulu”. Disponible jusquau 31 août.",
"aquaticAmigosNotes": "Contient “Laxototl magique”, “Le kraken dInkomplet”, et “Lappel dOctothulu”. Disponible jusquau 30 juin.",
"questSeaSerpentText": "Danger dans les profondeurs : Lattaque du serpent de mer !",
"questSeaSerpentNotes": "Vous vous sentez en veine grâce à vos réussites - c'est le moment idéal pour une excursion à l'hippodrome des hippocampes. Vous montez à bord du sous-marin aux Docks Diligents et vous vous installez pour le voyage à Dilatoire, mais vous êtes à peine submergé lorsqu'un impact secoue le sous-marin, et fait chavirer ses occupants. \"Que se passe-t-il ?\"<br><br>Vous regardez à travers un hublot à proximité et vous êtes surpris par le mur d'écailles scintillantes qui passe à côté. \"Serpent de mer !\" crie le capitaine @Witticaster par l'interphone. \"Préparez-vous, il revient !\" Lorsque vous saisissez les bras de votre siège, vos tâches inachevées clignotent devant vos yeux. \"Peut-être que si nous travaillons ensemble et les complétons\", pensez-vous, \"nous pouvons chasser ce monstre !\"",
"questSeaSerpentCompletion": "Battus grâce à votre engagement, les serpents de mer fuient, disparaissant dans les profondeurs. Quand vous arrivez à Dilatoire, vous poussez un soupir de soulagement avant de remarquer que @*~Seraphina~ venait vers vous avec trois œufs translucides retenus délicatement dans ses bras. « Tiens, tu mérites de les avoir», dit-elle. « Tu sais comment ty prendre avec les serpents de mer ! » Comme vous acceptez les œufs, vous faites à nouveau vœu de rester toujours constant dans la réalisation de vos tâches pour sassurer que lHistoire ne se répètera pas.",

View File

@@ -668,8 +668,8 @@
"backgrounds012022": "SET 92: Rilasciato Gennaio 2022",
"backgroundMeteorShowerNotes": "Osserva l'abbagliante spettacolo notturno di una pioggia di meteoriti.",
"backgroundSnowyFarmNotes": "Controlla che tutti stiano bene e al caldo nella tua fattoria coperta di neve.",
"backgroundMeteorShowerText": "Pioggia di Metore",
"backgroundPalmTreeWithFairyLightsText": "Palma con Lucine",
"backgroundMeteorShowerText": "Pioggia di Meteore",
"backgroundPalmTreeWithFairyLightsText": "Palma con Luci Fatate",
"backgroundPalmTreeWithFairyLightsNotes": "Posa vicino a una palma ornata di luci decorative.",
"backgroundSnowyFarmText": "Fattoria Innevata",
"backgrounds022022": "SET 93: Rilasciato a febbraio 2022",

View File

@@ -2534,8 +2534,8 @@
"armorArmoireShootingStarCostumeText": "Gonna Stellata",
"headSpecialWinter2022RogueText": "Finale Tonante",
"armorArmoireShootingStarCostumeNotes": "Apparentemente intessuta a partire dal cielo notturno stesso, questo abito fluido ti consente di aleggiare sopra tutti gli ostacoli sul tuo cammino. Aumenta la Costituzione di <%= con %>. Scrigno Incantato: Set della Polvere di Stella (oggetto 2 di 3).",
"weaponArmoireShootingStarSpellText": "Scintille di Polvere di Stella",
"weaponArmoireShootingStarSpellNotes": "Avvolgiti in un incantesimo di polvere di stelle per aiutarti a realizzare i tuoi desideri. Aumenta Forza e Intelligenza di <%= attrs %> ciascuno. Scrigno incantato: Set della Polvere di Stella (oggetto 3 di 3).",
"weaponArmoireShootingStarSpellText": "Scintille di Polvere di Stelle",
"weaponArmoireShootingStarSpellNotes": "Avvolgiti in un incantesimo di polvere di stelle per aiutarti a realizzare i tuoi desideri. Aumenta Forza e Intelligenza di <%= attrs %> ciascuno. Scrigno incantato: Set della Polvere di Stelle (oggetto 3 di 3).",
"armorSpecialWinter2022WarriorText": "Calza Sofficiosa",
"armorSpecialWinter2022WarriorNotes": "Chi dice che non puoi essere comodo e a tuo agio mentre combatti con le attività quotidiane? Aumenta la Costituzione di <%= con %>. Equipaggiamento in edizione limitata, inverno 2021-2022.",
"armorSpecialWinter2022MageText": "Cotta di Maglia Melograno",

View File

@@ -696,5 +696,12 @@
"backgroundAnimalsDenText": "Bosbeest's Hol",
"backgroundAnimalsDenNotes": "Beknus je in een Bosbeest's Hol.",
"backgroundBrickWallWithIvyText": "Bakstenen Muur met Klimop",
"backgroundBrickWallWithIvyNotes": "Bewonder een Bakstenen Muur met Klimop."
"backgroundBrickWallWithIvyNotes": "Bewonder een Bakstenen Muur met Klimop.",
"backgroundBeachWithDunesText": "Strand met duinen",
"backgroundBeachWithDunesNotes": "Ontdek een strand met duinen.",
"backgroundMountainWaterfallText": "Berg Waterval",
"backgroundMountainWaterfallNotes": "Bewonder een berg waterval.",
"backgroundSailboatAtSunsetText": "Zeilboot Bij Zonsondergang",
"backgroundSailboatAtSunsetNotes": "Geniet van de schoonheid van een zeilboot tijdens zonsondergang.",
"backgrounds062022": "SET 97: uitgebracht in juni 2022"
}

View File

@@ -1175,7 +1175,7 @@
"headArmoireRedHairbowText": "Rode strik",
"headArmoireRedHairbowNotes": "Word sterk, stoer en slim door het dragen van deze prachtige rode haarband! Verhoogt Kracht met <%= str %>, Weerbaarheid met <%= con %> en Intelligentie met <%= int %>. Betoverd kabinet: Rode haarbandset (voorwerp 1 van 2).",
"headArmoireVioletFloppyHatText": "Slappe paarse hoed",
"headArmoireVioletFloppyHatNotes": "Deze simpele hoed is doorweven met vele toverspreuken, waardoor hij een aangename paarse kleur heeft gekregen. Verhoogt Perceptie met <%= per %>, Intelligentie met <%= int %> en Weerbaarheid met <%= con %>. Betoverd kabinet: onafhankelijk voorwerp.",
"headArmoireVioletFloppyHatNotes": "Deze simpele hoed is doorweven met vele toverspreuken, waardoor hij een aangename paarse kleur heeft gekregen. Verhoogt Perceptie met <%= per %>, Intelligentie met <%= int %> en Weerbaarheid met <%= con %>. Betoverd kabinet: Violette Loungewear (voorwerp 1 van 3).",
"headArmoireGladiatorHelmText": "Gladiatorenhelm",
"headArmoireGladiatorHelmNotes": "Om en gladiator te zijn moet je niet alleen sterk zijn... maar ook geslepen. Vergroot intelligentie met <%= int %> en perceptie met <%= per %>. Betoverd kabinet: gladiatorset (voorwerp 1 van 3).",
"headArmoireRancherHatText": "Cowboyhoed",
@@ -1611,7 +1611,7 @@
"bodyMystery201901Notes": "These shimmering pauldrons are strong, but will rest on your shoulders as weightlessly as a ray of dancing light. Confers no benefit. January 2019 Subscriber Item.",
"bodyArmoireCozyScarfText": "Knusse Sjaal",
"bodyArmoireCozyScarfNotes": "This fine scarf will keep you warm as you go about your wintry business. Increases Constitution and Perception by <%= attrs %> each. Enchanted Armoire: Lamplighter's Set (Item 4 of 4).",
"headAccessory": "hoofdaccessoire",
"headAccessory": "Hoofdaccessoire",
"headAccessoryCapitalized": "Hoofdaccessoire",
"accessories": "Accessoires",
"animalEars": "Dierenoren",
@@ -2396,5 +2396,7 @@
"weaponSpecialSpring2022RogueNotes": "Een glanzende! Het is zo glimmend and glanzend en mooi en leuk en helemaal van jou! Verhoogt Kracht met <%= str %>. Beperkte oplage 2022 lenteuitrusting.",
"weaponSpecialSpring2022WarriorText": "Binnenstebuiten Paraplu",
"weaponSpecialSpring2022WarriorNotes": "Jakkes! Die wind was misschien iets sterker dan je dacht, he? Verhoogt Kracht met <%= str %>. Beperkte oplage 2022 lenteuitrusting.",
"weaponSpecialSpring2022MageText": "Forsythia Staf"
"weaponSpecialSpring2022MageText": "Forsythia Staf",
"armorArmoireSoftVioletSuitNotes": "Paars is een luxe kleur. Ontspan in stijl na je al je dagelijke taken hebt volbracht. Verhoogt Weerbaarheid en Kracht met <%= attrs %> elk. Betoverde kast: Violette Loungewear (voorwerp 2 van 3).",
"shieldArmoireSoftVioletPillowNotes": "De slimme krijger pakt een kussen in voor elke expeditie. Bescherm jezelf van door uitstel veroorzaakte paniek... zelfs terwijl je een dutje doet. Verhoogt Intelligentie met <%= int %>. Betoverde kast: Violette Loungewear (voorwerp 3 van 3)."
}

View File

@@ -105,9 +105,14 @@
"achievementSeeingRed": "Exército Vermelho",
"achievementSkeletonCrew": "Equipe Esqueleto",
"achievementBugBonanza": "Prosperidade de Inseto",
"achievementRosyOutlook": "Aspecto Rosado",
"achievementRosyOutlook": "Perspectiva Rosada",
"achievementVioletsAreBlue": "Violetas são Azuis",
"achievementSeasonalSpecialist": "Especialista Sazonal",
"achievementWildBlueYonderModalText": "Tu domesticaste todas as Montarias de Algodão Doce Azul!",
"achievementSeasonalSpecialistText": "Completou todas as missões sazonais de Primavera e Inverno: Caçada aos Ovos, Noel Caçador, e Encontre o Filhote!"
"achievementSeasonalSpecialistText": "Completou todas as missões sazonais de Primavera e Inverno: Caça aos Ovos, Pai Natal Caçador, e Encontre o Filhote!",
"achievementDomesticatedText": "Eclodiu todas as cores padrão das mascotes domesticadas: Furão, Poquinho-da-Índia, Galo, Porco Voador, Rato, Coelhinho, Cavalo e Vaca!",
"achievementDomesticated": "I-A-I-A-OH",
"achievementVioletsAreBlueModalText": "Coletou todas as Mascotes Algodão-doce Rosa!",
"achievementDomesticatedModalText": "Coletou todas as mascotes domesticadas!",
"achievementWildBlueYonderText": "Domesticou todas as Montarias de Algodão Doce Azul."
}

View File

@@ -132,5 +132,7 @@
"achievementBirdsOfAFeatherModalText": "Você coletou todos os mascotes voadores!",
"achievementGroupsBeta2022Text": "Você e seu grupo deram um feedback inestimável para ajudar a testar o Habitica.",
"achievementGroupsBeta2022ModalText": "Você e seu grupo ajudaram o Habitica, testando e dando o seu feedback!",
"achievementReptacularRumbleModalText": "Você coletou todos os mascotes do tipo réptil!"
"achievementReptacularRumbleModalText": "Você coletou todos os mascotes do tipo réptil!",
"achievementReptacularRumble": "Répteis Reptumbantes",
"achievementReptacularRumbleText": "Coletou todos os mascotes comuns do tipo réptil: Cobra, Jacaré, Pterodáctilo, Tartaruga, Tiranossauro, Tricerátops e Velociraptor!"
}

View File

@@ -505,6 +505,11 @@ const backgrounds = {
mountain_waterfall: { },
sailboat_at_sunset: { },
},
backgrounds072022: {
bioluminescent_waves: { },
underwater_cave: { },
underwater_statues: { },
},
timeTravelBackgrounds: {
airship: {
price: 1,

View File

@@ -1,5 +1,6 @@
import t from '../translation';
import prefill from './prefill';
import { EVENTS } from '../constants';
export default prefill({
baseHair1: { setPrice: 5, text: t('hairSet1') },
@@ -29,7 +30,7 @@ export default prefill({
setPrice: 5, availableFrom: '2021-09-28T08:00-04:00', availableUntil: '2021-10-31T20:00-04:00', text: t('supernaturalSkins'),
},
splashySkins: {
setPrice: 5, availableFrom: '2021-07-13T08:00-04:00', availableUntil: '2021-07-31T20:00-04:00', text: t('splashySkins'),
setPrice: 5, availableFrom: '2022-07-05T08:00-05:00', availableUntil: EVENTS.summer2022.end, text: t('splashySkins'),
},
winterySkins: {
setPrice: 5, availableFrom: '2021-12-23T08:00-05:00', availableUntil: '2022-01-31T20:00-05:00', text: t('winterySkins'),

View File

@@ -396,6 +396,11 @@ const armor = {
con: 9,
set: 'strawRaincoat',
},
fancyPirateSuit: {
con: 4,
int: 4,
set: 'fancyPirate',
},
};
const body = {
@@ -803,6 +808,10 @@ const head = {
per: 9,
set: 'strawRaincoat',
},
fancyPirateHat: {
per: 8,
set: 'fancyPirate',
},
};
const shield = {
@@ -1086,6 +1095,11 @@ const shield = {
int: 6,
set: 'musicalInstrumentOne',
},
treasureMap: {
int: 4,
str: 4,
set: 'fancyPirate',
},
};
const headAccessory = {

View File

@@ -57,6 +57,7 @@ const armor = {
202110: { },
202112: { },
202204: { },
202207: { },
301404: { },
301703: { },
301704: { },
@@ -118,6 +119,7 @@ const eyewear = {
202202: { },
'202204A': { mystery: '202204' },
'202204B': { mystery: '202204' },
202208: { },
301404: { },
301405: { },
301703: { },
@@ -190,6 +192,8 @@ const head = {
202112: { },
202202: { },
202206: { },
202207: { },
202208: { },
301404: { },
301405: { },
301703: { },

View File

@@ -398,7 +398,7 @@ spells.special = {
target: 'user',
notes: t('spellSpecialSeafoamNotes'),
canOwn () {
return moment().isBetween('2021-07-06T08:00-04:00', EVENTS.summer2021.end);
return moment().isBetween('2022-07-12T08:00-04:00', EVENTS.summer2022.end);
},
cast (user, target, req) {
if (!user.items.special.seafoam) throw new NotAuthorized(t('spellNotOwned')(req.language));

View File

@@ -42,6 +42,18 @@ export class BuyQuestWithGemOperation extends AbstractGemItemOperation { // esli
this.canUserPurchase(user, item);
}
canUserPurchase (user, item) {
if (item && item.prereqQuests) {
for (const prereq of item.prereqQuests) {
if (!user.achievements.quests[prereq]) {
throw new NotAuthorized(this.i18n('mustComplete', { quest: prereq }));
}
}
}
super.canUserPurchase(user, item);
}
async executeChanges (user, item, req) {
if (
!user.items.quests[item.key]

View File

@@ -46,20 +46,22 @@ export class BuyQuestWithGoldOperation extends AbstractGoldItemOperation { // es
throw new NotAuthorized(this.i18n('questNotGoldPurchasable', { key }));
}
this.checkPrerequisites(user, key);
this.canUserPurchase(user, item);
}
checkPrerequisites (user, questKey) {
const item = content.quests[questKey];
if (questKey === 'lostMasterclasser1' && !this.userAbleToStartMasterClasser(user)) {
canUserPurchase (user, item) {
if (this.getItemKey() === 'lostMasterclasser1' && !this.userAbleToStartMasterClasser(user)) {
throw new NotAuthorized(this.i18n('questUnlockLostMasterclasser'));
}
if (item && item.previous && !user.achievements.quests[item.previous]) {
throw new NotAuthorized(this.i18n('mustComplete', { quest: item.previous }));
if (item && item.prereqQuests) {
for (const prereq of item.prereqQuests) {
if (!user.achievements.quests[prereq]) {
throw new NotAuthorized(this.i18n('mustComplete', { quest: prereq }));
}
}
}
super.canUserPurchase(user, item);
}
executeChanges (user, item, req) {

View File

@@ -1,3 +1,4 @@
import moment from 'moment';
import nconf from 'nconf';
import { authWithHeaders } from '../../middlewares/auth';
import { model as Group } from '../../models/group';
@@ -22,7 +23,11 @@ import { getMatchesByWordArray } from '../../libs/stringUtils';
import bannedSlurs from '../../libs/bannedSlurs';
import apiError from '../../libs/apiError';
import highlightMentions from '../../libs/highlightMentions';
import { getAnalyticsServiceByEnvironment } from '../../libs/analyticsService';
const analytics = getAnalyticsServiceByEnvironment();
const ACCOUNT_MIN_CHAT_AGE = Number(nconf.get('ACCOUNT_MIN_CHAT_AGE'));
const FLAG_REPORT_EMAILS = nconf.get('FLAG_REPORT_EMAIL').split(',').map(email => ({ email, canSend: true }));
/**
@@ -188,6 +193,17 @@ api.postChat = {
throw new NotAuthorized(res.t('messageGroupChatSpam'));
}
// Check if account is newer than the minimum age for chat participation
if (moment().diff(user.auth.timestamps.created, 'minutes') < ACCOUNT_MIN_CHAT_AGE) {
analytics.track('chat age error', {
uuid: user._id,
hitType: 'event',
category: 'behavior',
headers: req.headers,
});
throw new BadRequest(res.t('chatTemporarilyUnavailable'));
}
const sanitizedMessageText = sanitizeMessageText(req.body.message);
const [message, mentions, mentionedMembers] = await highlightMentions(sanitizedMessageText);
let client = req.headers['x-client'] || '3rd Party';

View File

@@ -267,7 +267,11 @@ api.updateHero = {
const hero = await User.findById(heroId).exec();
if (!hero) throw new NotFound(res.t('userWithIDNotFound', { userId: heroId }));
if (updateData.balance) hero.balance = updateData.balance;
if (updateData.balance) {
await hero.updateBalance(updateData.balance - hero.balance, 'admin_update_balance', '', 'Given by Habitica staff');
hero.balance = updateData.balance;
}
// give them gems if they got an higher level
// tier = level in this context
@@ -323,7 +327,9 @@ api.updateHero = {
}
}
if (updateData.changeApiToken) hero.apiToken = common.uuid();
if (updateData.changeApiToken) {
hero.apiToken = common.uuid();
}
const savedHero = await hero.save();
const heroJSON = savedHero.toJSON();

View File

@@ -714,8 +714,8 @@ api.transferGems = {
throw new NotAuthorized(res.t('badAmountOfGemsToSend'));
}
await receiver.updateBalance(amount, 'gift_receive', sender._id, sender.profile.name);
await sender.updateBalance(-amount, 'gift_send', sender._id, receiver.profile.name);
await receiver.updateBalance(amount, 'gift_receive', sender._id, sender.auth.local.username);
await sender.updateBalance(-amount, 'gift_send', sender._id, receiver.auth.local.username);
// @TODO necessary? Also saved when sending the inbox message
const promises = [receiver.save(), sender.save()];
await Promise.all(promises);

View File

@@ -64,9 +64,15 @@ api.purchaseHistory = {
req.checkParams('memberId', res.t('memberIdRequired')).notEmpty().isUUID();
const validationErrors = req.validationErrors();
if (validationErrors) throw validationErrors;
const transactions = await Transaction
let transactions = await Transaction
.find({ userId: req.params.memberId })
.sort({ createdAt: -1 });
.sort({ createdAt: -1 })
.exec();
if (!res.locals.user.hasPermission('userSupport')) {
transactions = transactions.filter(t => t.transactionType !== 'create_bank_challenge');
}
res.respond(200, transactions);
},
};

View File

@@ -35,7 +35,7 @@ export async function socialEmailToLocal (user) {
).exec();
if (!conflictingUser) return socialEmail;
}
return null;
return undefined;
}
export async function loginSocial (req, res) { // eslint-disable-line import/prefer-default-export

View File

@@ -103,6 +103,8 @@ const bannedWords = [
'bullshitting',
'shiz',
'shit',
'shite',
'shits',
'shitty',
'shitting',
'shithole',

View File

@@ -74,14 +74,16 @@ export async function createChallenge (user, req, res) {
if (groupBalance >= prizeCost) {
// Group pays for all of prize
group.balance -= prizeCost;
await user.updateBalance(0, 'create_bank_challenge', challenge._id, challenge.name);
} else if (groupBalance > 0) {
// User pays remainder of prize cost after group
const remainder = prizeCost - group.balance;
group.balance = 0;
await user.updateBalance(-remainder, 'create_challenge', challenge._id, challenge.text);
await user.updateBalance(-remainder, 'create_challenge', challenge._id, challenge.name);
} else {
// User pays for all of prize
await user.updateBalance(-prizeCost, 'create_challenge', challenge._id, challenge.text);
await user.updateBalance(-prizeCost, 'create_challenge', challenge._id, challenge.name);
}
}

View File

@@ -58,6 +58,8 @@ schema.methods.updateHourglasses = async function updateHourglasses (userId,
amount,
reference,
referenceText,
currentAmount: this.consecutive.trinkets,
});
};

View File

@@ -5,7 +5,7 @@ import baseModel from '../libs/baseModel';
const { Schema } = mongoose;
export const currencies = ['gems', 'hourglasses'];
export const transactionTypes = ['buy_money', 'buy_gold', 'contribution', 'spend', 'gift_send', 'gift_receive', 'debug', 'create_challenge', 'create_guild', 'change_class', 'rebirth', 'release_pets', 'release_mounts', 'reroll', 'contribution', 'subscription_perks'];
export const transactionTypes = ['buy_money', 'buy_gold', 'spend', 'gift_send', 'gift_receive', 'debug', 'create_challenge', 'create_bank_challenge', 'create_guild', 'change_class', 'rebirth', 'release_pets', 'release_mounts', 'reroll', 'contribution', 'subscription_perks', 'admin_update_balance'];
export const schema = new Schema({
currency: { $type: String, enum: currencies, required: true },
@@ -13,6 +13,7 @@ export const schema = new Schema({
reference: { $type: String },
referenceText: { $type: String },
amount: { $type: Number, required: true },
currentAmount: { $type: Number },
userId: {
$type: String, ref: 'User', required: true, validate: [v => validator.isUUID(v), 'Invalid uuid for Transaction.'],
},
@@ -23,7 +24,17 @@ export const schema = new Schema({
});
schema.plugin(baseModel, {
noSet: ['id', '_id', 'userId', 'currency', 'transactionType', 'reference', 'referenceText', 'amount'], // Nothing can be set from the client
noSet: [
'id',
'_id',
'userId',
'currency',
'transactionType',
'reference',
'referenceText',
'amount',
'currentAmount',
], // Nothing can be set from the client
timestamps: true,
_id: false, // using custom _id
});

View File

@@ -559,5 +559,6 @@ schema.methods.updateBalance = async function updateBalance (amount,
amount,
reference,
referenceText,
currentAmount: this.balance,
});
};