Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Combined Message Pages/Redesign #15310

Open
wants to merge 65 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
65 commits
Select commit Hold shift + click to select a range
85ecd5e
split component prepare new views / states
negue May 12, 2024
c3cb54c
extract empty and disabled state as components
negue May 12, 2024
7ce1136
fix empty state mail icon
negue May 12, 2024
6c60c10
first logic switching between modes, move page to /private-messages/i…
negue May 15, 2024
17b2760
extract autoCompleteHelper.js
negue May 25, 2024
40a13d8
style header + start new message input
negue May 25, 2024
8b6a032
style plus button + focus input
negue May 25, 2024
1016f8c
state logic, types for sanity
negue Jun 5, 2024
3f9c673
WIP PM new Message started
negue Jun 14, 2024
4348d5e
Merge remote-tracking branch 'origin/develop' into negue/ui/private-m…
negue Jun 15, 2024
b3c511b
add /members/username test
negue Jun 15, 2024
68f91d0
first design changes to messageCard
negue Oct 22, 2023
790cda2
delete private message or chat - based on the mode
negue Oct 22, 2023
54ac09e
copy as todo
negue Oct 22, 2023
2adae6c
mention links to modal
negue Oct 22, 2023
59821ba
report chat or private message
negue Oct 22, 2023
ccda33e
WIP likeButton
negue Oct 26, 2023
a3b778c
likeButton styling
negue Oct 29, 2023
c6cd91a
hide like on private message cards
negue Oct 29, 2023
b868ee0
fix unit test
negue Nov 2, 2023
33513b5
replace copy as todo - to just a copy to clipboard
negue Nov 2, 2023
f49ee93
style changes
negue Nov 3, 2023
30fb131
menu position + like button width
negue Nov 3, 2023
ad78a4d
dropdown items background + like font
negue Nov 3, 2023
b432a3a
fix like button padding
negue Nov 5, 2023
dec16dc
move api endpoints and tests around to group inbox methods + like fo…
negue Nov 5, 2023
cefa0e7
restyle system messages
negue Nov 9, 2023
721f7fa
Dropdown Radius and Padding
negue Nov 17, 2023
ca47547
WIP system messages
negue Nov 24, 2023
57197a2
fix lint
negue Jan 7, 2024
3069243
copy delta commit of allowing liking own private messages
negue Jan 27, 2024
f86484e
enable liking private messages
negue Feb 1, 2024
b74c145
fix menu non hovered item icon color
negue Feb 3, 2024
789b6e5
fix import path
negue Feb 3, 2024
a5c51d5
ignore background on system messages
negue Feb 10, 2024
f64a4fa
requested changes + migration
negue Feb 15, 2024
75bf685
update migration to update the unique id to some messages and delete …
negue Feb 22, 2024
186e3f0
migration based on users pagination
negue Feb 29, 2024
9ebaaf4
fix(migration): use Promise.all
Mar 5, 2024
d197115
change to bulkWrites per User, and all messages in one run (of a user)
negue Mar 7, 2024
1321905
check for array
negue Mar 19, 2024
c9040e3
use rest operator ...
negue Mar 20, 2024
40b8641
skip sorting to get the users
negue Mar 25, 2024
3faf05c
remove migration, disable like for private messages without uniqueMes…
negue Apr 6, 2024
130574b
lean+bulkWrite for likes, add time checks for like and auth for furth…
negue Apr 16, 2024
23fd6e6
add a limit 2 get the messages by uniqueId
negue Apr 24, 2024
82399fb
Merge remote-tracking branch 'origin/negue/ui/private-messages' into …
Aug 28, 2024
64e29d6
Adding a simple server start script
negue Sep 1, 2024
78bcaf0
remove pinned nodemon dep
negue Sep 1, 2024
df6f37d
Merge branch 'simple-server-start-script' into negue/ui/combined-mess…
negue Sep 1, 2024
e6e7565
fix inbox controller/tests
negue Sep 1, 2024
d056dfb
fix / requested style changes
negue Sep 1, 2024
fb1f435
Merge remote-tracking branch 'origin/develop' into negue/ui/combined-…
negue Sep 12, 2024
1cbdf23
fix empty state padding /
negue Sep 12, 2024
66484f0
hide avatar weapons on messages - fix avatar spacing on messages
negue Oct 4, 2024
de4ce30
Merge remote-tracking branch 'origin/develop' into negue/ui/combined-…
negue Oct 4, 2024
522ee9c
Hourglass Simplification (#15323)
SabreCat Oct 29, 2024
c366459
chore(sprites): update subproject
SabreCat Oct 30, 2024
aacf8d2
fix(layout): tighten cancellation note
SabreCat Nov 1, 2024
c0c18cb
fix(subs): Google wording and HG escape
SabreCat Nov 1, 2024
028b94b
chore(testing): fake g1g1 dates
SabreCat Nov 1, 2024
c341f0d
fix(subs): don't hide HG preview entirely
SabreCat Nov 1, 2024
e88ff5c
fix(subs): center next hourglass message
SabreCat Nov 4, 2024
ac77d6a
Merge remote-tracking branch 'origin/develop' into negue/ui/combined-…
negue Nov 4, 2024
da9bc9e
working validatedTextInput.vue within start-new-conversation-input-he…
negue Nov 19, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -47,5 +47,5 @@ webpack.webstorm.config

# mongodb replica set for local dev
mongodb-*.tgz
/mongodb-data
/mongodb-data*
/.nyc_output
2 changes: 1 addition & 1 deletion habitica-images
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@
"start:simple": "node ./website/server/index.js",
"debug": "gulp nodemon --inspect",
"mongo:dev": "run-rs -v 5.0.23 -l ubuntu1804 --keep --dbpath mongodb-data --number 1 --quiet",
"mongo:test": "run-rs -v 5.0.23 -l ubuntu1804 --keep --dbpath mongodb-data-testing --number 1 --quiet",
"postinstall": "git config --global url.\"https://\".insteadOf git:// && gulp build && cd website/client && npm install",
"apidoc": "gulp apidoc",
"heroku-postbuild": ".heroku/report_deploy.sh"
Expand Down
1 change: 0 additions & 1 deletion test/api/unit/libs/bug-report.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ describe('bug-report', () => {
USER_HOURGLASSES: 0,
USER_ID: userId,
USER_LEVEL: 1,
USER_OFFSET_MONTHS: 0,
USER_PAYMENT_PLATFORM: undefined,
USER_SUBSCRIPTION: undefined,
USER_TIMEZONE_OFFSET: 0,
Expand Down
515 changes: 52 additions & 463 deletions test/api/unit/libs/cron.test.js

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -715,7 +715,7 @@ describe('Purchasing a group plan for group', () => {
const mysteryItem = { title: 'item' };
const mysteryItems = [mysteryItem];
const consecutive = {
trinkets: 3,
trinkets: 4,
gemCapExtra: 20,
offset: 1,
count: 13,
Expand Down
542 changes: 152 additions & 390 deletions test/api/unit/libs/payments/payments.test.js

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions test/api/unit/libs/payments/stripe/oneTimePayments.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,7 @@ describe('Stripe - One Time Payments', () => {
customerId,
paymentMethod: 'Gift',
gift,
autoRenews: false,
gemsBlock: undefined,
});
});
Expand Down
3 changes: 3 additions & 0 deletions test/api/unit/libs/payments/stripe/subscriptions.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,7 @@ describe('Stripe - Subscriptions', () => {
paymentMethod: 'Stripe',
sub: sinon.match({ ...sub }),
groupId: null,
autoRenews: true,
});
});

Expand All @@ -197,6 +198,7 @@ describe('Stripe - Subscriptions', () => {
paymentMethod: 'Stripe',
sub: sinon.match({ ...sub }),
groupId,
autoRenews: true,
});
});

Expand Down Expand Up @@ -231,6 +233,7 @@ describe('Stripe - Subscriptions', () => {
paymentMethod: 'Stripe',
sub: sinon.match({ ...sub }),
groupId,
autoRenews: true,
});
});
});
Expand Down
56 changes: 56 additions & 0 deletions test/api/v3/integration/members/GET-members_username.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import {
generateUser,
translate as t,
} from '../../../../helpers/api-integration/v3';
import common from '../../../../../website/common';

describe('GET /members/username/:username', () => {
let user;

before(async () => {
user = await generateUser();
});

it('validates req.params.username', async () => {
await expect(user.get('/members/username/')).to.eventually.be.rejected.and.eql({
code: 400,
error: 'BadRequest',
message: t('invalidReqParams'),
});
});

it('returns a member public data only', async () => {
// make sure user has all the fields that can be returned by the getMember call
const member = await generateUser({
contributor: { level: 1 },
backer: { tier: 3 },
preferences: {
costume: false,
background: 'volcano',
},
secret: {
text: 'Clark Kent',
},
});
const memberRes = await user.get(`/members/username/${member.auth.local.username}`);
expect(memberRes).to.have.all.keys([ // works as: object has all and only these keys
'_id', 'id', 'preferences', 'profile', 'stats', 'achievements', 'party',
'backer', 'contributor', 'auth', 'items', 'inbox', 'loginIncentives', 'flags',
]);
expect(Object.keys(memberRes.auth)).to.eql(['local', 'timestamps']);
expect(Object.keys(memberRes.preferences).sort()).to.eql([
'size', 'hair', 'skin', 'shirt',
'chair', 'costume', 'sleep', 'background', 'tasks', 'disableClasses',
].sort());

expect(memberRes.stats.maxMP).to.exist;
expect(memberRes.stats.maxHealth).to.equal(common.maxHealth);
expect(memberRes.stats.toNextLevel).to.equal(common.tnl(memberRes.stats.lvl));
expect(memberRes.inbox.optOut).to.exist;
expect(memberRes.inbox.canReceive).to.exist;
expect(memberRes.inbox.messages).to.not.exist;
expect(memberRes.secret).to.not.exist;

expect(memberRes.blocks).to.not.exist;
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ describe('POST /user/buy-mystery-set/:key', () => {

expect(res.data).to.eql({
items: JSON.parse(JSON.stringify(user.items)), // otherwise dates can't be compared
purchasedPlanConsecutive: user.purchased.plan.consecutive,
purchasedPlanConsecutive: JSON.parse(JSON.stringify(user.purchased.plan.consecutive)),
});
expect(res.message).to.equal(t('hourglassPurchaseSet'));
});
Expand Down
104 changes: 104 additions & 0 deletions test/api/v4/inbox/POST-inbox_message_like.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
import find from 'lodash/find';
import {
generateUser,
translate as t,
} from '../../../helpers/api-integration/v4';

/**
* Checks the messages array if the uniqueMessageId has the like flag
* @param {InboxMessage[]} messages
* @param {String} uniqueMessageId
* @param {String} userId
* @param {Boolean} likeStatus
*/
function expectMessagesLikeStatus (messages, uniqueMessageId, userId, likeStatus) {
const messageToCheck = find(messages, { uniqueMessageId });

expect(messageToCheck.likes[userId]).to.equal(likeStatus);
}

// eslint-disable-next-line mocha/no-exclusive-tests
describe('POST /inbox/like-private-message/:messageId', () => {
let userToSendMessage;
const getLikeUrl = messageId => `/inbox/like-private-message/${messageId}`;

before(async () => {
userToSendMessage = await generateUser();
});

it('Returns an error when private message is not found', async () => {
await expect(userToSendMessage.post(getLikeUrl('some-unknown-id')))
.to.eventually.be.rejected.and.eql({
code: 404,
error: 'NotFound',
message: t('messageGroupChatNotFound'),
});
});

it('Likes a message', async () => {
const receiver = await generateUser();

const sentMessageResult = await userToSendMessage.post('/members/send-private-message', {
message: 'some message :)',
toUserId: receiver._id,
});

const { uniqueMessageId } = sentMessageResult.message;

const likeResult = await receiver.post(getLikeUrl(uniqueMessageId));
expect(likeResult.likes[receiver._id]).to.equal(true);

const senderMessages = await userToSendMessage.get('/inbox/messages');

expectMessagesLikeStatus(senderMessages, uniqueMessageId, receiver._id, true);

const receiversMessages = await receiver.get('/inbox/messages');

expectMessagesLikeStatus(receiversMessages, uniqueMessageId, receiver._id, true);
});

it('Allows to likes their own private message', async () => {
const receiver = await generateUser();

const sentMessageResult = await userToSendMessage.post('/members/send-private-message', {
message: 'some message :)',
toUserId: receiver._id,
});

const { uniqueMessageId } = sentMessageResult.message;

const likeResult = await userToSendMessage.post(getLikeUrl(uniqueMessageId));
expect(likeResult.likes[userToSendMessage._id]).to.equal(true);

const messages = await userToSendMessage.get('/inbox/messages');
expectMessagesLikeStatus(messages, uniqueMessageId, userToSendMessage._id, true);

const receiversMessages = await receiver.get('/inbox/messages');

expectMessagesLikeStatus(receiversMessages, uniqueMessageId, userToSendMessage._id, true);
});

it('Unlikes a message', async () => {
const receiver = await generateUser();

const sentMessageResult = await userToSendMessage.post('/members/send-private-message', {
message: 'some message :)',
toUserId: receiver._id,
});

const { uniqueMessageId } = sentMessageResult.message;

const likeResult = await receiver.post(getLikeUrl(uniqueMessageId));

expect(likeResult.likes[receiver._id]).to.equal(true);

const unlikeResult = await receiver.post(getLikeUrl(uniqueMessageId));

expect(unlikeResult.likes[receiver._id]).to.equal(false);

const messages = await userToSendMessage.get('/inbox/messages');

const messageToCheck = find(messages, { id: sentMessageResult.message.id });
expect(messageToCheck.likes[receiver._id]).to.equal(false);
});
});
51 changes: 8 additions & 43 deletions test/common/libs/cron.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -183,16 +183,14 @@ describe('cron utility functions', () => {
});

describe('getPlanContext', () => {
const now = new Date(2022, 5, 1);

function baseUserData (count, offset, planId) {
return {
purchased: {
plan: {
consecutive: {
count,
offset,
gemCapExtra: 25,
gemCapExtra: 26,
trinkets: 19,
},
quantity: 1,
Expand All @@ -213,52 +211,19 @@ describe('cron utility functions', () => {
};
}

it('monthly plan, next date in 3 months', () => {
it('elapsedMonths is 0 if its the same month', () => {
const user = baseUserData(60, 0, 'group_plan_auto');
user.purchased.plan.perkMonthCount = 0;

const planContext = getPlanContext(user, now);

expect(planContext.nextHourglassDate)
.to.be.sameMoment('2022-08-10T02:00:00.144Z');
});

it('monthly plan, next date in 1 month', () => {
const user = baseUserData(62, 0, 'group_plan_auto');
user.purchased.plan.perkMonthCount = 2;

const planContext = getPlanContext(user, now);

expect(planContext.nextHourglassDate)
.to.be.sameMoment('2022-06-10T02:00:00.144Z');
const planContext = getPlanContext(user, new Date(2022, 4, 20));
expect(planContext.elapsedMonths).to.equal(0);
});

it('multi-month plan, no offset', () => {
const user = baseUserData(60, 0, 'basic_3mo');

const planContext = getPlanContext(user, now);

expect(planContext.nextHourglassDate)
.to.be.sameMoment('2022-06-10T02:00:00.144Z');
});

it('multi-month plan with offset', () => {
const user = baseUserData(60, 1, 'basic_3mo');

const planContext = getPlanContext(user, now);

expect(planContext.nextHourglassDate)
.to.be.sameMoment('2022-07-10T02:00:00.144Z');
});

it('multi-month plan with perk count', () => {
const user = baseUserData(60, 1, 'basic_3mo');
user.purchased.plan.perkMonthCount = 2;
it('elapsedMonths is 1 after one month', () => {
const user = baseUserData(60, 0, 'group_plan_auto');

const planContext = getPlanContext(user, now);
const planContext = getPlanContext(user, new Date(2022, 5, 11));

expect(planContext.nextHourglassDate)
.to.be.sameMoment('2022-07-10T02:00:00.144Z');
expect(planContext.elapsedMonths).to.equal(1);
});
});
});
2 changes: 1 addition & 1 deletion website/client/.eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ module.exports = {
extends: [
'habitrpg/lib/vue',
],
ignorePatterns: ['dist/', 'node_modules/'],
ignorePatterns: ['dist/', 'node_modules/', '*.d.ts'],
rules: {
'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'off',
'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off',
Expand Down
5 changes: 5 additions & 0 deletions website/client/src/assets/css/sprites/spritesmith-main.css
Original file line number Diff line number Diff line change
Expand Up @@ -40127,6 +40127,11 @@
width: 28px;
height: 28px;
}
.notif_subscriber_reward {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/notif_subscriber_reward.png');
width: 28px;
height: 28px;
}
.npc_bailey {
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/npc_bailey.png');
width: 60px;
Expand Down
Binary file added website/client/src/assets/images/confetti.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed website/client/src/assets/images/subscriber-food.png
Binary file not shown.
13 changes: 11 additions & 2 deletions website/client/src/assets/scss/button.scss
Original file line number Diff line number Diff line change
Expand Up @@ -94,8 +94,7 @@

.btn-secondary,
.dropdown > .btn-secondary.dropdown-toggle:not(.btn-success),
.show > .btn-secondary.dropdown-toggle:not(.btn-success)
{
.show > .btn-secondary.dropdown-toggle:not(.btn-success) {
background: $white;
border: 1px solid transparent;
color: $gray-50;
Expand Down Expand Up @@ -262,6 +261,16 @@
box-shadow: none;
}

.btn-flat,
.dropdown > .btn-flat.dropdown-toggle:not(.btn-success),
.show > .btn-flat.dropdown-toggle:not(.btn-success) {
&.with-icon {
.svg-icon.color {
color: var(--icon-color);
}
}
}

.btn-cancel {
color: $blue-10;
}
Expand Down
12 changes: 0 additions & 12 deletions website/client/src/assets/scss/colors.scss
Original file line number Diff line number Diff line change
Expand Up @@ -78,15 +78,3 @@ $gold-color: #FFA624;
$hourglass-color: #2995CD;

$purple-task: #925cf3;

.gray-200 {
color: $gray-200 !important;
}

.purple-300 {
color: $purple-300 !important;
}

.white {
color: $white !important;
}
Loading
Loading