freeCodeCamp / chapter

A self-hosted event management tool for nonprofits
BSD 3-Clause "New" or "Revised" License
1.92k stars 360 forks source link

As a user, I can unsubscribe from a specific chapters emails. #274

Open QuincyLarson opened 4 years ago

QuincyLarson commented 4 years ago

Depends on #106

allella commented 4 years ago

@ceciliaconsta3 so we agree on a label. Is the checkbox suggestion vs switch for accessibility? What's the experience when a screen reader encounters a label and a checkbox vs a label and a swtich?

@allella A label is definitely the surest bet. If, and it sounds like, we will use the Subscribe component in a form alongside other elements to complete an event sign-up, (if MVP won't have a User Account Settings page) we should treat the Subscribe switch as a checkbox using checkbox role instead. It'll get sent at form submission with the other fields.

I think "Active" color as Subscribe/unchecked status and grey/disabled for Unsubscribe/checked status would do. Copied this from #107 since this is a UI conversation. https://github.com/freeCodeCamp/chapter/issues/107#issuecomment-562417958

ceciliaconsta3 commented 4 years ago

That's a good question; just used Narrator to review the site you referenced and because the switches are essentially set up as checkboxes, I had no problem receiving the status information (ya know, aside from normal screenreader difficulties). I'll look for a less optimized site using switches to compare later.

Functionality: Technically, based on the usage defined, if we are waiting until the RSVP form is sent (subscription depending on form submission) we require a checkbox (form input) or button (performs some action) here as a field in the RSVP form. If the subscription is being set independently of the RSVP, say on toggle, switch it is. This article has a cool comparison Checkboxes/buttons both are natively supported in modern screenreaders and make semantic sense like labels. For reference/competitive analysis, I see Meetup uses buttons/checkboxes on desktop and switches on their app for the same task (probably due to screen real estate).

Visually: We can totally create switch appearing checkboxes. Although, there can be some ambiguity when it comes to switch visual cues (which side is on or off? Is it the side I want?).

Current UI: Reviewing our Figma mockups, we don't have a view for a RSVP confirmation screen yet so I'm going by the current minimal/high contrast design.

allella commented 4 years ago

107 mentions the likelihood of needing to subscribe to chapter notifications separate from rsvp notifications, so we can let the context guide the UI elements.

Thanks for the examples of when to use each, and I agree that poorly done switches can be hard to figure out off from on, but well done switches make me smile. We previously had guidance on checkbox vs radio button, but now we have all these new, fancy UI elements :)

Perhaps the rsvp subscribe is a form field checkbox since that UI likely has other form components and a submit button. Then, for a chapter or event landing page we might like a switch to avoid the user having to toggle and submit for a preference that can be toggled with a single action.

When using a switch, is it customary to also show a flash message or similar reinforcement that your action completed successfully?

ceciliaconsta3 commented 4 years ago

Seeing #107 has been updated. I agree with your use cases. Gotta sprinkle that UI sugar.

I don't think an alert confirmation it's necessar, the switch visual itself does that. It'd become another thing to handle on mobile. Let's just update its status in DOM (screenreader), perhaps add a title for tooltip (visual/SR), and change its color (high visual). This could apply to all switches going forward.

Madalena-15 commented 4 years ago

@allella @ceciliaconsta3 while I understand accessibility plays a vital role in the world of web (I am partially blind myself), I believe using switches for appropriate elements are much better than checkboxes in mobile layout.

I can't speak for others, but whenever I am browsing and scrolling on the mobile web, there have been times that I unintentionally have tapped on the button or any sort of link element and it would easily perform an unwanted action, especially even if I lightly tap on the link element as well. With switches, I noticed it doesn't easily toggle with light or accidental taps, I have tested this by playing with the switches in the Material UI link provided, which confirms my theory on this.

There are some minor setbacks with switches, but I think we can solve them ourselves?

@allella

I think "Active" color as Subscribe/unchecked status and grey/disabled for Unsubscribe/checked status would do.

@ceciliaconsta3

Visually: We can totally create switch appearing checkboxes. Although, there can be some ambiguity when it comes to switch visual cues (which side is on or off? Is it the side I want?).

I completely agree with the concept that certain colours should be applied to the switches based on their status. The downside of switches is whenever I come across one in the site or app, the colours used are not a massive contrast and I tend to find it confusing. If we were to do this and implement our own colours, the "active" colour should be either dark or bold in comparison to the light-medium greyed-out status.

When using a switch, is it customary to also show a flash message or similar reinforcement that your action completed successfully?

Well, I was thinking this could be good for if a user were to unsubscribe and there would be a pop-up box asking the user if they are sure to go ahead (in case they unsubscribe by accident)

allella commented 4 years ago

I'm not a UI person, so I'll defer to the designers on the correct elements and actions. Most of what I can offer on the front-end is semantic correctness and SEO.

Is the design team in a position to start fleshing out some of these next pages? I've linked the other related issues so more focused questions or comments about specific interfaces can be directed to those threads.

(see the terminology for more on the italics entities)

Madalena-15 commented 4 years ago

Is the design team in a position to start fleshing out some of these next pages? I've linked the other related issues so more focused questions or comments about specific interfaces can be directed to those threads.

Well, we were supposed to have some sort of design team meeting to discuss moving onto the next stage, but not have heard anything since. (I will explain further in Discord)

(see the terminology for more on the italics entities)

Actually, now you have mentioned terminology, I was looking at them the other day and I think I got a pretty good idea of what each term mean, except one which is niggling at the back of my mind (but decided just to go with my assumption). That term is chapter.

How I understood it in English layman term is chapter is a branch of an organization. For example, Women Who Code is an organization. They have branches (chapters) all over the USA, such as New York City, San Francisco, Chicago. Since the organisation have multiples branches (chapters), the user can search for their local (branch/chapter) by the name Women Who Code [New York City/San Francisco/Chicago]

Am I correct with my assumption on this term?

ceciliaconsta3 commented 4 years ago

@madaleneaza-design Quick comment, just thought of this. Rather than a popup box, we can simply replace the button with "You are now subscribed text" as well.

Madalena-15 commented 4 years ago

@ceciliaconsta3 That is a good idea in term of both user experience and web optimisation/performance. Thank you for this, that is helpful. :)

QuincyLarson commented 4 years ago

@allella @madaleneaza-design It might be simpler to just list out all the chapters a user is subscribed to on their settings page, and have the ability to toggle them on and off there.

For example, on iOS, instead of having different notification settings for each app, Apple has its own notification dashboard where you can toggle each on and off (with 3 tiers of prominence for each notification). Then we could just add this to the User Settings/profile page (https://github.com/freeCodeCamp/chapter/issues/262).

What do you all think about this?

Madalena-15 commented 4 years ago

@allella @madaleneaza-design It might be simpler to just list out all the chapters a user is subscribed to on their settings page, and have the ability to toggle them on and off there.

@QuincyLarson I agree. For users, it is an easier experience as they only have to navigate to one place to change any settings in comparison to certain settings in different places, which a user would have to memorise in case they want to make changes in the future.

I like the example of IOS and their structure of settings you have provided. In a moment, I will look onto my Ipad settings and create a rough layout and implement the settings of notifications for chapters.

So, just to confirm, will there be a user setting page?

allella commented 4 years ago

@QuincyLarson @madaleneaza-design I'm not saying this is an either or situation and I think we're all in agreement that a subscription page is eventually useful.

However, I feel we still want / need UI elements on the event and chapter landing pages to toggle on / off subscriptions to a chapter or event. I say this because it's a familiar pattern to have a "join", "follow" button on platforms like Meetup Groups and Facebook Groups, which are effectively our chapter pages

Also, a subscription management page may only be useful for turning chapter notifications off. For instance, on Meetup.com's Manage Subscriptions page you can only edit existing group subscriptions. There's no way to opt-in to something new because then you'd need to list all possible groups, or else have a search feature. Facebook doesn't offer any Group notification options under their Notifications as they expect users to opt-in and opt-out via the Group landing pages.

This issue is specific to chapter notifications, but we've also been talking about event notifications since #108 expects event notifications for the MVP. It's hard to figure if a subscription management page would be useful for event notifications. For example, if someone has previously registered for dozens of events then would the page show dozens of old events?

In summary, a subscription management page may be limited to the use case of turning off existing chapter notifications.

That said, if you'd like to create an MVP user story for a manage chapter subscriptions page then feel free to do so and we can do all of the above, plus links to opt out in emails.

tomiiide commented 4 years ago

The list of emails we are sending to users is discussed and tracked in this Google Doc. https://docs.google.com/document/d/1VE0zqJPgTOdAOTP2Bcmdjved8uCbAoFxOjuKFs93krk/edit?usp=sharing

allella commented 3 years ago

Oliver shared thoughts on https://github.com/freeCodeCamp/chapter/issues/99#issuecomment-926492529 about helping users understand the impact of unsubscribing from a chapter. For example, what happens if a user is subscribed to an event and unsubscribes from a chapter.

Ravichandra-C commented 3 years ago

@ojeytonwilliams , @allella , Should I add a Switch Component showing the status userChapterRoles.interested of the chapter on the chapter/[id] and dashboard/chapter/[id] pages if a user has logged in otherwise we will not display switch component ?

allella commented 3 years ago

@Ravichandra-C Oliver is going to move that field into a new table, probably called _user_chapterdetails

Perhaps you can add the UI element and link it to the database once those changes are made?

Ravichandra-C commented 3 years ago

@allella Sure.

allella commented 2 years ago

@ojeytonwilliams @Ravichandra-C

Related to this issue, I notice how easy it is to unsubcribe from a saved search with Craigslist without being logged in.

It seems like a simple subscription ID + user ID + token pattern.

https://accounts.craigslist.org/savesearch/unsubscribe?subID=########&userID=#########&t=_2pPfymWJ90ZfsDzz6k62A

I mentioned a "hash" / token idea awhile back to allow for unsubscribing without having to login and that may be even easier than I'd imagined at the time.

I suspect there are at least two approaches to using a token / hash. 1) Generate and save a unique token with the database entry when a subscription is created 2) Use a hashing pattern based on some set of values and then regenerated that value as needed to send unsubscribe links and to authenticate an unsubscribe link.

I've seen the first idea done with Drupal's password reset token. They actually store the token in the database instead of having to generate the value any time it's needed. Once a token is used a new one is generated and saved for the next time it's needed.

I'd lean toward the first idea for the sake of simplicity as well because when we're doing things like sending "Upcoming Email" #275 we wouldn't need to worry about generating a hash, since it would already be part of the database. The same would apply for event subscriptions and chapter subscriptions #274

In any case, I thought I'd share since some approach like this will be needed unless we're going to require a user to be logged in to unsubscribe from notifications, which shouldn't be necessary in my opinion.

@bappyasif this may be a conversation and issue you can help with too.

allella commented 2 years ago

Also related to #107 #276 and pretty much all issues with an Email label.

bappyasif commented 2 years ago

@allella yeah, sure, i would love to, and thanks a lot for considering, much appreciated :)

i also gone through your stapled issue list already, and after reading this latest reply from you, i tend to agree that if it's a possibility that user login is not necessary to unsubscribe from notification, thats awesome, but how 'chapter' would know which user is that, if not 'logged in' though?! im not really affluent in backend programming as of yet!! sorry if its too much of a noob question, thanks :)

ojeytonwilliams commented 2 years ago

We might be breaking laws in various jurisdictions if we don't provide an easy unsubscribe link. I'm not a lawyer, so I couldn't tell you if it's illegal to require someone to be logged in to unsubscribe, but it's obnoxious UX and not a risk we should take.

but how 'chapter' would know which user is that, if not 'logged in' though?!

That's an excellent question. I'm not sure if this is the perfect approach, but I would do this: add a signed JSON web token to the unsubscribe link. That token would contain the data the server needs to unsubscribe. For example, if they're unsubscribing from a event it would be

{
  "userId": "the-user-id",
  "eventId": "the-event-id"
}

Then, when the user clicks on an unsubscribe link, the server would verify the token, decode it and unsubscribe the user from that event.

we wouldn't need to worry about generating a hash, since it would already be part of the database

I think it's fine to create a hash/jwt on the fly, it's pretty fast. My machine can produce roughly 100,000 jwts in a second, it doesn't seem like it's a bottleneck we need to worry about for the MVP.

ojeytonwilliams commented 2 years ago

While I'm not dead set against storing unsubscribe ids in the db, I think the JWT approach is simple and flexible. All we need to do to extend it (say we want to support unsubscribing from organisations) is to add more properties to the JSON we're signing, rather than tinkering with the DB.

allella commented 2 years ago

That's fine. I thought the JWT was more for login, but if you can easily use it to do tokens for things like unsubscribe, then it's one less field to worry about in the database.

ojeytonwilliams commented 2 years ago

Yep, that's how it's normally used, but it's just a signed JSON object. You can put in whatever data you like.

bappyasif commented 2 years ago
{
  "userId": "the-user-id",
  "eventId": "the-event-id"
}

@ojeytonwilliams thanks for helping me understand, but a follow up question regarding this, "user_id", doesnt that mean user is already signed in?! or its taking from 'user cache'?

sorry about all these questions, im just trying to learn, as i go on, hope that's okay :)

allella commented 2 years ago

@bappyasif Oliver was suggesting the userId and eventId values could be used to generated a token for each email that is sent from the instance.

As an example, a user would receive a link in their personalized email that allows them to unsubscribe with a click /unsubscribe?eventID=9999&userID=222&jwToken=_2pPfymWJ90ZfsDzz6k62A However, the jwToken value would be checked to confirm the user who clicked the link is the same person who received the specific email.

Without a token, it would be easy for someone to write a script that generates eventID and userID combinations and visits those URLs in an attempt to unsubscribe users without their approval.

This same concept would apply to unsubscribing from chapter emails, which is the topic of this issue. A URL for unsubscribing would be included at the bottom of any chapter emails and a user could click that link, without needing to be logged in, and the presence of the jwToken would validate that they are the intended recipient.

/unsubscribe?chapterID=6789&userID=222&jwToken=_kw9902ijdljsk290w99lkpcv

bappyasif commented 2 years ago

@allella yeah it's making sense now, i somehow missed that 'integral' part of this conversation which is 'email', thanks for clearing that up, much appreciated :)

on added note, how do you want me to help with this issue?!

ojeytonwilliams commented 2 years ago

Hey @bappyasif I think there's a reasonable sketch of what's required in the above discussion. I recommend having a play with the app and seeing what you can come up with.

It's worth taking a look at the login resolver in https://github.com/freeCodeCamp/chapter/blob/main/server/src/controllers/Auth/resolver.ts and generateToken in https://github.com/freeCodeCamp/chapter/blob/main/server/src/services/AuthToken.ts so you can see how we currently deal with JWTs in the app.

bappyasif commented 2 years ago

@ojeytonwilliams thyanks for those attached scripts, auth token make a lot more sense now, functionality wise, i have never done it before in any of my attempts with js, so quite a learning experiece, all of these :)

on another note, i saw a lot of thorw new Error' in 'login resolver' when there is any sort of conflicts or exceptions, doesn't it supposed to stop executing rest of code or app?! sorry, if that's too much of a rhetorical question!!

i surely should play around with 'chapter app' to see whats what, thanks for suggesting it, much appreciated :)

ojeytonwilliams commented 2 years ago

on another note, i saw a lot of thorw new Error' in 'login resolver' when there is any sort of conflicts or exceptions, doesn't it supposed to stop executing rest of code or app?! sorry, if that's too much of a rhetorical question!!

Yep, that's pretty much what happens. When you throw an error inside Express middleware then it will catch it and not run any more middleware (other than error handlers).

So, throwing an error is a good way to stop something which should not do any more processing.

The idea here https://github.com/freeCodeCamp/chapter/blob/0bf3c3a9eb60f99b670d691614b6b1df651f98a3/server/src/controllers/Auth/resolver.ts#L81-L84

is that if there isn't a user with that email address, they can't log in and so the login process has to be stopped. Throwing an error does that perfectly well.

bappyasif commented 2 years ago

@ojeytonwilliams understood, that's pretty neat and straightforward, thanks a lot for explaining it, just wanted to be sure, much appreciated :)

@ojeytonwilliams @allella how can i help with this issue, please let me know, thanks :)

ojeytonwilliams commented 2 years ago

how can i help with this issue, please let me know, thanks :)

Well, we've discussed how we want to implement this a fair bit in this issue. If that makes sense to you, great. If you have some specific queries about how to proceed, please ask away.

However, if you want something more straightforward to work on while you get up to speed, please take a look at the issues labelled Good First Issue. If you're not sure what to do, then your best bet is to start with one of those. You can always come back to this later.

bappyasif commented 2 years ago

i guess, i better start from there then, i'll keep it in my tab meanwhile, thanks a lot @ojeytonwilliams

allella commented 2 years ago

@megajon I don't recall if the mockup you made had anything for a profile or subscription page. My guess is no, but the mockup link we had in the README is no longer working. Is there a way you can reactivate that mockup, or else share an export (PDF or screenshots) for future reference?

Thanks

allella commented 2 years ago

@ojeytonwilliams

Since we're revisiting this conversation in the chat, I thought to mention that we may not have gotten into the details of needing a vocabulary, and UI elements, to distinguish between "joining / leaving" a chapter vs "subscribing / unsubscribing".

The schema allows for a _user_chapter_ record and then the true / false subscribed value to manage if the user will receive notifications for that chapter, like notifications about upcoming events.

The seed data seems to be automatically adding users into a few _chapterusers records, so I'm automatically a member and subscribed. image

When unsubscribing, the UI still shows that I'm a member, with no option to change membership status. image

I'm assuming we'll need some additional UI elements to "Join" or "Leave", or some other vocabulary, similar to what I hinted at above.

allella commented 2 years ago

Our Terminology has that a member can "can follow and receive notifications from a chapter" a chapter, but we should consider other wording in the application.

The word "follow" may be confusing since it's hard to differentiate from the notifications / subscription options a user has as a member.

"Join" and "Leave" are the most obvious and would be familiar for those coming from Meetup.

allella commented 2 years ago

@ojeytonwilliams I forgot out this privacy setting. I don't think we discussed it for MVP, but another option for an account settings page would be the ability to show yourself as "Private Member" or something like that.

https://github.com/freeCodeCamp/chapter/issues/263#issuecomment-566316803

ojeytonwilliams commented 2 years ago

Agreed. If we have the potential to share anything private (email address, real names etc) we definitely need an option to hide them. It's probably safest to have that be the default.

allella commented 2 years ago

@Sboonny was asking about this issue and https://github.com/freeCodeCamp/chapter/issues/263 and the decision on what we're collecting and how a user can control their data will impact determine the content of the Privacy and Terms of Service pages.