Global Announcements with User Tracking (copyable)

This was inspired by a recent tutorial by @Robert_Petitto (who else? :rofl:)

For an app I am currently working on, there is a requirement to support Global Announcements. The basic requirements are:

  1. An Administrator can create an announcement and target it at a specific group of users
  2. When a user opens the app, any new announcements will be front and centre on their dashboard
  3. The user can view the announcement and mark it as read
  4. Administrators can track how many users have read each announcement, and which users

Requirements 1 to 3 are easy. Just add a User Specific Boolean to the Announcements table and we’re done. But requirement 4 is a little trickier. The problem is that you can’t get at user specific data for doing things like rollups, etc. So I’ve been mulling this over for a few days, and after watching Bob’s tutorial earlier today I had a sudden flash of inspiration :grinning:

Here is how I ended up doing it:

  • Announcements are presented as an Inline List
  • When a user taps an Announcement, a custom action writes their UserID to a USC, and then does a View Details
  • In my Announcements table, I have a “Read By” column. This is a Basic Text column, but actually contains a joined list of the UserID’s of all users that have read the announcement. This list is built dynamically as each user marks the announcement as read
  • I then take that “Read By” column and use a Split Text column to create an array of UserID’s
  • This is in turn used to create a multi-relation back to my Users table (this provides access to a list of users that have read the announcement)
  • And finally, I do a rollup on that relation to get a count of users that read the announcement

I’ve put together a demo and added it to my “Community Demo’s” app. Here is what the demo looks like:

Note that when this goes into my “real” app, Row Owners and Roles will be enabled, so users won’t be able to see the counts or who else read each announcement. But I left those disabled for the purpose of the demo. Also in the demo users can mark announcements as “Unread”. This option won’t be available in the “real” app.

The app is copyable, so feel free to grab it and play around with it.

Would also be interested to hear of other approaches to this, and in particular if I’ve missed something obvious and overcomplicated it (which I usually do) :rofl:

14 Likes

Thank you for the tutorial and explaination

1 Like

Well done!

1 Like

Thanks!
Curious to know how you would approach this?
What I have seems to work okay, but I’m always open to learning better/alternative ways to get things done :slightly_smiling_face:

Hi Darren, what does this step look like? I am assuming there is a custom action when they “mark as read” but I dont know how to keep adding new values (UserIDs) to a basic text field without overwriting it.

  • When a user taps an announcement, their User ID is written to a User Specific Column (usc-user)
  • Then there are 3 columns in the Announcements table that help dynamically build the list:
    • tp-first-user - this is a Template column that just mirrors the contents of usc-user
    • tp-subsequent-users - another Template column that contains the current contents of Read By, a comma (,), and usc-user
    • ite-new-read-by - an if-then-else column that determines which of the two templates to use when the user marks the announcement as read. If Read By is empty, use the first one, otherwise use the second one.
  • Then when the user taps the ‘Mark as Read’ button, the Read By column is updated to the result of the if-then-else column.

Note that my method doesn’t remove users from the list when they mark an announcement as “Unread” (that wasn’t a requirement for my app). But @Lucas_Pires and @Robert_Petitto showed how this can be done with their “Trebuchet Method”. If you watch Bob’s video, you’ll see that he explicitly covers that step.

1 Like

Has anyone ever figured out how to remove a specific chunk of text from a joined list of values? (Assuming that the joined list isn’t being dynamically generated and is a static list that has been written to the sheet already)

Closest I’ve seen was @Jeff_Hager doing a bunch replacements using a blank column. But they were very specific use cases. I’ve yet to see a general solution, and I doubt that it will be possible until we get some string manipulation methods in the GDE.

PS. I’d be overjoyed to be proven wrong on this :grin:

1 Like

Yeah, I have a pretty non-user friendly method that I am going to try to make this work. String manipulation would be huge!

Could be that @Lucas_Pires has an ace up his sleeve…

2 Likes

nice! hope so

Was just thinking about this. I’ve seen that a few people have also asked for Regex capability in the GDE. Whilst this would be awesome, it could be a double-edged sword. Regex is incredibly powerful, but if you don’t know what you’re doing it’s very easy to write regular expressions that become huge resource hogs. I can imagine folks going to town with regex in the GDE, and then wondering why their apps are grinding to a halt. So maybe not such a good idea. But vanilla string functions like left(), right(), substr(), etc… yes please!

2 Likes

Some days I really wish I could switch these two replacement fields around.

image

Sometimes I want to dynamically set the value to be replaced, and sometimes I want to just type in a replacement value instead of creating another column (especially a blank/empty column just for the replacement). Would really help to make a lot of things easier,…along with a full list of string manipulation options :wink: . I’ve hit a few walls where code is easier than no-code and I’ve had to jump through a few hoops to make something work.

Do you have an example of a list and the value you would want removed? Is the value that you want removed a certain value, or is it kind of unlimited what it could be?

3 Likes

uh-oh… here we go again… :fishing_pole_and_fish: :rofl:

3 Likes

hehe, I’m a glutton for punishment.

It would just be a comma separated list of Row IDs that are written to the sheet by an add row action.

ie. QmGPN3dQScStbkkcg8Ebzg, B05-ku22R8qWvbebbysRlQ, DsxAk8YbTp2hX3kRCyEPlw

Removing B05-ku22R8qWvbebbysRlQ, for example.

One idea I’ve considered is to use a multi-step action to clear the column AND write the existing array to another column that then gets turned into an inline list for them to re-select from. That would really only work for small arrays where it’s not too cumbersome for the user to have to re-select the correct items.

1 Like

Brilliant! I have an immediate use case for this :clap: :clap: :clap: :clap:

Definitely not easy since it’s Row IDs. The only thing I could think of would involve a Split Text column, a relation to a sheet that has those Row IDs in rows, and some variation of the Trebuchet method to rebuild a Joined List of Row IDs minus the Row ID you want removed to overwrite your existing joined list.

1 Like