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

Scheduled post indicator #8522

Merged

Conversation

harshilsharma63
Copy link
Member

Summary

Added scheduled post indicator for mobile

Ticket Link

Fixes https://mattermost.atlassian.net/browse/MM-62284

Checklist

  • Added or updated unit tests (required for all new features)
  • Has UI changes
  • Includes text changes and localization file updates
  • Have tested against the 5 core themes to ensure consistency between them.
  • Have run E2E tests by adding label E2E iOS tests for PR.

Device Information

This PR was tested on: iOS emulator

Screenshots

Screenshot 2025-01-27 at 6 21 46 PM

Release Note

None

@harshilsharma63 harshilsharma63 marked this pull request as ready for review January 28, 2025 11:05
const theme = useTheme();
const styles = getStyleSheet(theme);

const [scheduledPostCount] = React.useState(125);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This 125 is hardcoded just for demo. It will later be replaced with actual count.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this PR, or in a future PR?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the next week or two. It will be in there before we merge feature branch into main.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please put a TODO comment that this value needs to be replaced. Just so that it won't get forgotten.

Copy link
Member Author

@harshilsharma63 harshilsharma63 Jan 29, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll work on integrating this today in a separate PR.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

scheduledPostCount is now. props, so this is removed now.

Copy link
Contributor

@rahimrahman rahimrahman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've "accidentally" reviewed this yesterday but realized it was a draft.

@@ -1,13 +1,94 @@
{
"object": {
"pins": [
{
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please revert changes to this file.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

Copy link
Contributor

@rahimrahman rahimrahman Feb 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The changes in this file is still showing up. Can you make sure it's fully reverted?

Comment on lines +992 to +994
"scheduled_post.channel_indicator.link_to_scheduled_posts.text": "See all.",
"scheduled_post.channel_indicator.multiple": "{count} scheduled messages in channel.",
"scheduled_post.channel_indicator.single": "Message scheduled for {dateTime}.",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need the .? I don't see any other messages having dots.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are a lot of messages ending in a full stop, such as settings_display.crt.desc, server.websocket.unreachable etc. If we need to display a full stop in UI, it has to go in here.

@@ -149,6 +150,8 @@ const Channel = ({
nativeID={channelId}
/>
</View>
{/*scheduled post indicator goes here*/}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably don't need the comments anymore.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

const theme = useTheme();
const styles = getStyleSheet(theme);

const [scheduledPostCount] = React.useState(125);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why 125?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Completely arbitrary. This will be picked from local database once integrated with it.

<FormattedTime
timezone={getUserTimezone(currentUser)}
isMilitaryTime={isMilitaryTime}
value={1768902936000}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why this value?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Completely arbitrary. This will be picked from local database once integrated with it.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same, add a TODO as instruction to replace with proper value. It will stand up hopefully in the main PR.

@@ -0,0 +1,107 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't forget unit test for this component.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After feature complete. Please be rest assured we will add the tests.

<FormattedTime
timezone={getUserTimezone(currentUser)}
isMilitaryTime={isMilitaryTime}
value={1768902936000}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same, add a TODO as instruction to replace with proper value. It will stand up hopefully in the main PR.

@@ -0,0 +1,359 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How can there be a snapshot file when the channel.test.tsx doesn't have toMatchSnapshot()?

And thank you for not doing toMatchSnapshot().

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I must have added it and removed it but didn't remove the snapshot file.

expect(getByText(/See all./)).toBeTruthy();
});

it('should render multiple scheduled posts indicator for thread', async () => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

duplicate with above?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nope, above one is for channels and this one is for threads. The text changes based on isThread prop, as being tested here.

);

const timeElement = await screen.findByTestId('scheduled_post_indicator_single_time');
expect(timeElement).toBeTruthy();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it really a military time? Just knowing the testId is there enough to say that it is military time? Why?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added check for it now.

);

const timeElement = await screen.findByTestId('scheduled_post_indicator_single_time');
expect(timeElement).toBeTruthy();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above. Just knowing the timeElement exists doesn't really tell me that it's regular 12-hour vs military time. Is there another way to prove this?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added check for it now.

);

const timeElement = await screen.findByTestId('scheduled_post_indicator_single_time');
expect(timeElement).toBeTruthy();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same, but how would I know the user is missing?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Its just that it doesn't break when user is missing, no special behavior occurs on user missing that can be tested. Its a "just for safety" test, not useful.

@@ -149,6 +150,8 @@ const Channel = ({
nativeID={channelId}
/>
</View>
{/*This count is hardcoded but will be removed during integration work*/}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add a TODO: on it?

Copy link
Member Author

@harshilsharma63 harshilsharma63 Feb 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can, but the ESlint doesn't like TODOs in code, so I have to add {/* eslint-disable-next-line no-warning-comments */} to ignore that warning, so its not worth it. Its not like this will be missed, its a feature branch work. All PRs will be incomplete y themselves and we'll end up adding dozens of TODOs everywhere. Not worth it.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i've added the TODO and the corresponding eslint fix anyways. LMK if you want me to continue adding those.

Comment on lines 93 to 102
it('does not render posts while switching channels', async () => {
const mockedChannelSwitch = jest.mocked(useChannelSwitch);
mockedChannelSwitch.mockReturnValue(true);

renderWithEverything(
<Channel {...getBaseProps()}/>,
{database},
);

expect(screen.queryByTestId('channel.post_draft')).toBeNull();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Duplicated above again?

jest.clearAllMocks();
});

it('does not render posts while switching teams', async () => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does not render post or does not render scheduled post or draft?

@@ -0,0 +1,104 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test file feels a little off. The two tests are duplicated?

And there are no story to tell here.

If a test is saying that there's no post when switching teams, can you show there are post when not switching team?

I guess there needs to be some sort of a base. Like what do I expect the channel file to display when it has basic props.

Then go from there...

Copy link
Member Author

@harshilsharma63 harshilsharma63 Feb 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm deleting this test for now, its a very large existing component and my changes in it are minor. Adding tests for the whole channel component is beyond the scope of this PR and feature.

@@ -97,7 +97,7 @@ const ScrollToEndView = ({
() => ({
transform: [
{
translateY: withTiming(showScrollToEndBtn ? -80 - keyboardOverlap - bottomAdjustment : 0, {duration: 300}),
translateY: withTiming(showScrollToEndBtn ? -100 - keyboardOverlap - bottomAdjustment : 0, {duration: 300}),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change delta of "-20" has not much of a significant, but it would be nice to know why it was made. Diff in screenshot would help, but I'm happy with quick explanation.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is how it looks with -80

Screenshot 2025-02-03 at 12 36 16 PM

This is how it looks with -100

Screenshot 2025-02-03 at 12 49 08 PM

adjustment of 20 is all we need. Maybe a few pixels here or there more, but thats to be done later during a UX review.


let scheduledPostText: React.ReactNode;

if (scheduledPostCount <= 0) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Qurious: Can scheduledPostCount ever be less than 0?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I accidentally set a negative value once, so I handled it. However, since it doesn’t make sense according to the specification, I replaced it with an “===“ case.


if (scheduledPostCount <= 0) {
return null;
} else if (scheduledPostCount === 1) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happens if it's more than 1? You will not show dateTime at all?

Why not?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correct, because we cannot show date and time of all scheduled posts in a small indicator in channel. See the attached screenshot in PR description for example.

@harshilsharma63 harshilsharma63 requested review from rahimrahman and larkox and removed request for Rajat-Dabade February 3, 2025 10:18
@larkox
Copy link
Contributor

larkox commented Feb 4, 2025

@abhijit-singh There was a discussion not long ago about the amount of banners taking real state at the top of the screen, and this PR just made me realize we also have a lot of stuff happening at the bottom.

In particular... we can have someone typing in the channel, while we have scheduled messages, while we are writing a priority message, with several lines of text and a couple of attachments. Not sure from the top of my head if we have any other element living in that space.

Taking that into consideration, and also the existing banners on the top, are we ok with continuing with this approach for scheduled messages in the channel?

@larkox
Copy link
Contributor

larkox commented Feb 4, 2025

@harshilsharma63 Have you tested how well / bad this interact with the "User X is typing on the channel" message?

Copy link
Contributor

@larkox larkox left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, just a couple questions and comments, but nothing really blocking.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The changes here seem to affect no matter if the scheduled post message is visible or not. Is that intended? Is there any visual change due to this?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks right both with and without the scheduled post indicator with the same change.

Here is a video of with and without scheduled post indicator. Maybe I'll need to add some extra spacing conditionally, but will figure it out later.

Screen.Recording.2025-02-04.at.4.42.06.PM.mov
Screen.Recording.2025-02-04.at.4.40.44.PM.mov

Comment on lines +120 to +125
<Text style={styles.link}>
<FormattedMessage
id='scheduled_post.channel_indicator.link_to_scheduled_posts.text'
defaultMessage='See all.'
/>
</Text>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the plan here? For this to be a touchable, or for the whole banner to be a touchable?

We are not yet implementing this part because we don't have the screen, right? Or am I missing something?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

User will be able to click here to go the screen, which doesn't exist yet. hence, only text for now.

const timeElement = await findByTestId('scheduled_post_indicator_single_time');
expect(timeElement).toBeVisible();
expect(getByText(/Message scheduled for/)).toBeVisible();
});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are a couple of prop that can be undefined that you are not testing: scheduledPostCount and isThread. isThread may not be needed, since undefined is falsy, and you are setting the default value for scheduledPostCount to 0, but I guess it wouldn't hurt to add test to make sure those defaults never change.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

scheduledPostCount will default to 0 once I integrate it with local database and will never be undefined.

@harshilsharma63
Copy link
Member Author

LGTM, just a couple questions and comments, but nothing really blocking.

Great catch! I've filed https://mattermost.atlassian.net/browse/MM-62871 for addressing it.

@harshilsharma63 harshilsharma63 merged commit cb2e36e into create_scheduled_post_api_integration Feb 4, 2025
6 checks passed
@harshilsharma63 harshilsharma63 deleted the scheduled_post_indicator branch February 4, 2025 11:18
harshilsharma63 added a commit that referenced this pull request Feb 4, 2025
* WIP

* Separate component for core and custom options

* WIP

* WIP

* WIP

* unified options into single component

* Scheduled post menu ready

* Displayed date time picker by default

* WIP

* Lint fix

* i18n fix

* removed unused screen

* API call sent successfully

* Added user time format preference

* review fixex and improvements

* Handled loading sttae

* Handled loading sttae

* Handled mentions and files and priority

* Cleanup

* lint fix

* i18n fix

* WIP

* Displayed error snackbar

* Fixed time used for debugging

* Lint fix

* review fixex and improvements

* Renamed a file

* Adding tests

* Adding tests

* lint fix

* cleanup

* Added draft_input tests

* test: Add comprehensive tests for SendAction component

* Added send_action tests

* lint fix

* test: Add comprehensive test coverage for useHandleSendMessage hook

* test: Add test for scheduled post creation in send message hook

* fix: Mock createScheduledPost function in test to resolve matcher error

* WIP tests

* test: Add tests for SnackBar component

* Added snack bar tests

* Cleanup

* test: Add empty test file for scheduled post picker

* test: Add tests for ScheduledPostOptions component

* test: Improve ScheduledPostOptions test coverage and error handling

* test: Update ScheduledPostOptions test suite with new database and timezone mocking

* test: Fix timeout issues in ScheduledPostOptions test suite

* Added scheuidled post picker tests

* test: Add empty test file for scheduled post footer

* test: Add comprehensive tests for ScheduledPostFooter component

* feat: Add animatedFooterPosition prop to ScheduledPostFooter test

* test: Add tablet rendering test for ScheduledPostFooter

* test: Update ScheduledPostFooter test mocks and remove unused imports

* test: Add mocks for BottomSheet context in scheduled post footer tests

* Added scheudled post footer test

* test: Add comprehensive tests for handle_send_message hook

* Enhanced handle send message tests

* cleanup

* Added missing snapshots

* test: Add error logging and force logout validation for scheduled post tests

* Updated test

* used toBeVisible instead of toBeTruthy

* test: Update test assertions to use toHaveBeenCalledWith

* test: Add assertions to prevent sendMessage when send button is disabled

* test: Replace snapshot tests with explicit UI element checks

* test improvements

* Deleted unused snapshots

* Updated snaopshot

* feat: Add close button ID for scheduled post options bottom sheet

* test: Add mock scheduling flow to scheduled post options test

* Fixed incorrect test

* scheudled post test enhancement

* minimised a test

* Scheduled post indicator (#8522)

* WIP

* WIP

* DFisplayed everything correctly

* Lint fix

* handled thread and padding

* removed a comment

* Fixed i18n

* test: Add empty test file for scheduled post indicator component

* test: Add tests for ScheduledPostIndicator component

* test: Rewrite ScheduledPostIndicator tests with improved coverage

* test: Update scheduled post indicator test setup with TestHelper

* fix: Replace non-existent addPreferencesToServer with TestHelper.setPreference

* refactor: Update ScheduledPostIndicator tests to use operator.handleConfigs

* refactor: Use renderWithEverything and consistently pass database prop

* Added tests for scheduled_post_indicator

* test: Add channel screen test file

* test: Add comprehensive tests for Channel component

* refactor: Remove unused import and clean up whitespace in channel test file

* refactor: Update Channel component tests with database and renderWithEverything

* refactor: Update Channel test cases to remove async/await and add type

* test: Wrap channel screen render in act() to handle async updates

* fix: Resolve unmounted renderer error in Channel snapshot test

* test: Remove unnecessary async act in channel test snapshot

* fix: Resolve unmounted renderer issue in channel screen test

* Added chanels test

* test: Add empty test file for thread screen

* test: Add tests for Thread component with rendering and call feature scenarios

* cleanup

* Mock up0date

* temperorily removed a flaky test

* review fixes

* Fixed a test

* Fixed a test

* Fixed a test
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants