-
Notifications
You must be signed in to change notification settings - Fork 0
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
#6, feat: Add form that allows user to invite another user to list! #28
Conversation
…n exisiting user to a list. Use the shareList firebase func to add existing user to list. Co-authored-by: Maha Ahmed <[email protected]>
Visit the preview URL for this PR (updated for commit 8183e2d): https://tcl-77-smart-shopping-list--pr28-rc-ma-share-shopping-aq7r2o1j.web.app (expires Sun, 08 Sep 2024 00:54:44 GMT) 🔥 via Firebase Hosting GitHub Action 🌎 Sign: b77df24030dca7d8b6561cb24957d2273c5e9d72 |
It was great working with you this week Maha! I know we are not supposed to worry about styling, and I love that the acceptance criteria gave us some freedom! Do you think it would be a good idea to add something like a horizontal row (hr tag) between the two forms where that arrow is pointing? How do you feel about placeholder text? What do you think about putting in "Enter e-mail address. . ." in the text field? |
I'm so glad we got some more practice with React Hot Toast this week! What do you think about changing the messages? Something like The important parts we got done are: |
src/views/ManageList.tsx
Outdated
Invite User | ||
</button> | ||
</form> | ||
<Toaster /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
note: I don't think there needs to be 2 <Toaster />
elements in this. It should only need one.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So cool! Maha and I were wondering that! We figured one form === one toaster element.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah! We really were curious about that. I thought it was a per form as well. After looking into it some more, its good practice to "import { Toaster } from 'react-hot-toast' " into the root of the application , probably in our App.tsx file. By doing that, we will only need to " import { toast } from 'react-hot-toast' " into any of our needed files, but we wont need to place any elements since all our app components will have access to it :)
src/views/ManageList.tsx
Outdated
console.log("Button clicked! Inviting user!"); | ||
e.preventDefault(); | ||
|
||
const trimmedEmailName = validateTrimmedString(emailName); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
praise: I love seeing this util function validateTrimmedString
being used again! How cool!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I do too! Except I don't think it needs to be 😄 because the input element has the email
type, it isn't possible to get this component into a state where email
has any whitespace, the input trims it for you already:
https://html.spec.whatwg.org/multipage/input.html#email-state-(type=email)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
and for what it's worth, I didn't know this either 😄 I knew email
wouldn't let an empty string through (the benefit of using email
is that you don't have to worry about figuring out if the string is an email, which can't be an empty string). But I discovered through testing that it was also stripping the white space, which is very good to know!
src/views/ManageList.tsx
Outdated
|
||
try { | ||
await toast.promise(shareList(listPath, currentUser, trimmedEmailName), { | ||
loading: "sharing list with existing user", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm so glad we got some more practice with React Hot Toast this week!
What do you think about changing the messages? Something like
Successfully invited ${emailName} to your list!
for success? Something likeOops! Failed to invite ${emailName} to your list. Please try again!
for error?
The important parts we got done are:
A. The toasts are working!
B. The variable shows up in string interpolation.
I think this comment was more for Maha but I really like changing the messages to be a bit more descriptive! It would allow another way for the user to see like "who did i just invite?". 😅
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nothing wrong with answering questions! We can all work together. 😄
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes! I like that idea too. I was playing around in the useAuth.tsx file, and I noticed we have access to user.name and can invoke the list owner/user's name into our notifications, but it would be so cool if we could insert the invited user's name instead of their email !!!!
src/views/ManageList.tsx
Outdated
@@ -20,10 +22,13 @@ const purchaseTimelines = { | |||
}; | |||
|
|||
export function ManageList({ listPath }: Props) { | |||
const { user: currentUser } = useAuth(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
question: Was there a reason to call useAuth()
here? I know the user is needed on line 110 and I'm just curious if it was considered adding the user
prop to the <ManageList />
in App.tsx
and add it to the props in the call here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It was not! That's all we could think to do since currentUser had to come from somewhere.
I'm not really sure where to put this so I'm just throwing it in a PR comment over all. I noticed when I typed in the email I am signed up with and an email of a not currently existing in the DB user I got a successful message both times. Reading over the acceptance criteria
I think it should get an error at least if an email is passed of a user that does not currently exist within the application. I'm not sure if it should send some type of error if the user tries to share the list with themselves acceptance-wise but it may be nice to think about! Screen.Recording.2024-08-28.at.11.41.04.PM.mov |
Wow! I love how we noticed that at the exact same time :) "Async" hahah. You're absolutely right!! I just realized that it does in fact send a "successful notification" regardless of whether the user exists or not (any email was working). After looking at the shareList function that checks whether the invited user exists before sharing the list, the condition was written to "exit" the function early through a return statement if the "invited user" didn't exist. I learned that JavaScript considers a function "successful" if it returns a value or resolves itself without returning an error even if the function never completes. I believe then, the toast promise's error block didn't register the function exiting early as an "error". So interesting! Below I've screenshotted the before and after to fix the issue. Thanks for your detailed review @bbland1 ! What do you think @RossaMania ? ![]() ![]() |
Great catches you guys! It's not letting me reply to comments directly! Yes. I agree that throwing an actual Error object with a message would help! I feel like the message should say something like "Unable to share list". A message like "Recipient doesn't exist" could cause security concerns. It could be seen as it has just confirmed to somebody that that is not valid user information. |
That is awesome @eternalmaha! I saw it and I was like ooo I'm not sure I can describe it well so chose to take the screen recording lol 😅! I also think getting the message clear so not to cause concerns is important @RossaMania! |
@RossaMania I think editing our wording in the notifications sent to the user to be more clear is a great suggestion! I think including that the user is "unable to share list" as you mentioned is important. I think it is also a good idea to include why the list can't be shared so the user is able to troubleshoot, that doesn't cause them unecessary alarm. Perhaps "Unable to share list. Verify user has an active account !" ? I'm also down to make some basic styling changes to the appearance as well when we meet tomorrow to review and finalize all the suggested changes :) |
…th every email entered
…ications across entire app and removed unecessary Toaster elements in child components
…ailed email invite
So cool! @eternalmaha just got done meeting!
|
src/views/ManageList.tsx
Outdated
return `Successfully invited ${emailName} to your list!`; | ||
}, | ||
error: () => { | ||
return `Oops! Failed to invite ${emailName} to your list. Please verify correct email!`; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
praise: I really like this update to have the email name in the messages!
First off, I want to say that you’ve done a fantastic job with the ManageList component! The way you've structured the core functionality is clear, and your use of react-hot-toast for user feedback adds a nice, polished touch to the user experience. Also, the validation checks you’ve implemented are spot-on, ensuring that only valid data gets processed. 🚀 That said, I have a suggestion that could make the code even more maintainable, and it's one of the things @tannaurus called out for in our code as well, which I think is a great thing to be mindful of when building React apps: 😄 To further enhance the structure, consider breaking the ManageList component down into smaller, focused components like ItemForm, InviteForm, and PurchaseTimelineSelector. This would not only keep the code more organized and easier to manage but would also make these components more reusable across the app, saving time and effort in future development. By separating the item addition and user invitation logic into distinct components, we can improve the overall clarity of the code, making it much easier to test and debug. Additionally, this approach would significantly boost the readability of the code and lay a strong foundation for any future enhancements or updates, ensuring that the code remains clean and maintainable as the project grows. Again, excellent work on what you’ve built. The functionality is well-implemented, and the comment above is just a suggestion at this point, and can be implemented as a separate issue on it's own in upcoming future. |
src/views/ManageList.tsx
Outdated
} | ||
|
||
if (currentUser === null) { | ||
toast.error(`You are not logged in! Cannot invite.`); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it would be best to not render this component at all if the user is not signed in instead of notifying the user that they cannot do this operation after they have already attempted to do so
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes please! We were getting an odd message (that I can't remember right now), and that null-check solved the issue.
BUT, thinking about it now, we could just do a ternary operator like,
{currentUser && //code here}
right?
Edited to add: I'm also going to try it out here in a bit!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yup, that's correct! @bbland1 has been working to make this part of the codebase much more straight forward, so this shouldn't be an issue for much longer 😄 https://github.com/the-collab-lab/tcl-77-smart-shopping-list/pull/27/files
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes please! @zahrafalak I agree wholeheartedly! At this point, I feel like our app is getting to a nice size, and I was thinking about bringing up refactoring some elements into separate components this week.
|
src/views/ManageList.tsx
Outdated
|
||
const trimmedEmailName = validateTrimmedString(emailName); | ||
|
||
if (!trimmedEmailName) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Similar to my note above, we can remove this check: it's not possible to hit it.
src/views/ManageList.tsx
Outdated
@@ -76,6 +85,44 @@ export function ManageList({ listPath }: Props) { | |||
} | |||
}; | |||
|
|||
const handleInvite = async ( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could all of this new logic be its own component that is rendered here instead? There's a problem developing in this file where 1. the component is doing too many things (re: this other comment I left on PR #23) and 2. now there's a function in this component called handleSubmit
along side two different forms, making it hard to understand what that function is doing unless you read through its definition. This can be solved quickly by pushing this logic into its component and rendering it here instead 😄
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes please! I have an idea of what I want to do! I can work on this!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
WooooHoooo!!!!!
…orm submission and uses the `shareList` function from the Firebase API to add the existing user to the list. This feature enhances collaboration and sharing within the application.
…put type email. Corrected aria-label for handleInvite submit button
…e assertion of User for shareList function to only allow user to share list if logged in
For an example of how to fill this template out, see this Pull Request.
Description
We want to allow users to invite others to existing shopping lists so they can manage them with friends or family. We created a form in the ManageList view that allows the user to enter an email to invite an existing user to a list. It's in addition to the form that allows them to add items to that list. The user can submit this form with both the mouse and the Enter key. If the other user exists, the user is alerted that the list was shared with a React Hot Toast notification. If the other user does not exist, the list will not be shared and user will be notified!
This uses event listeners, and the shareList function from the firebase.ts!
We learned that it is important to keep it simple. While it may feel like we're reinventing the wheel even though we went from JavaScript to TypeScript in week 3, this is still a CRUD app. It was so cool to go through the different files and see how all the different arguments and props were passed!
Related Issue
closes #6
Acceptance Criteria
The ManageList view shows a form that allows the user to enter an email to invite an existing user to a list, in addition to the
form that allows them to add items to that list.
The input that accepts the email has a semantic label element associated with it
The user can submit this form with both the mouse and the Enter key
If the other user exists, the user is alerted that the list was shared
If the other user does not exist, the user is shown an error message that explains the problem
Type of Changes
enhancement
Updates
Before
After
Testing Steps / QA Criteria