How to structure stateful nested components to auto-update a timestamp

hi! I could use some design help on the best way to leverage function components and live components.

I’m building an activity stream where each event has a timestamp. I want to display this timestamp in a “time ago” format like “3m”, “2d”, “5w”, etc. Displaying it this way rules out (I think) a library like GitHub - github/time-elements: Web component extensions to the standard <time> element. because I want to have customized rules for when it flips from, say, days to weeks. I also don’t want the phrase to say “ago” for UX purposes. However, it may be simpler to bite the bullet and use a frontend library like this so I can move on with my life.

My thought was to use LiveView to recompute the relative values every so often and push changes to the client. This would give me full control over the formatting and unit cutover, as well as be awesome and totally sweet because Elixir. I am not sure how to architect such a feature.

My first implementation, which displayed only a static timestamp, was built with the activity stream as a single Live View that rendered each item as a stateless function component. Now that I want to introduce a dynamic timestamp into my previously stateless component I am stuck - I can’t render a Live Component from within my function component, so I’m looking at having each item be its own child Live View within the parent activity stream Live View. That gives me the control and dynamism I need, but I lose some ability, provided by the function component, to abstract the item markup.

Or, maybe I could render each item as a Live Component, but because Live Components are not their own processes it’s more complicated to instruct them to refresh their timestamps - I’d have to keep track of each item from within the parent and have the parent notify all its children when it’s time to refresh. Not a big deal, but feels clumsy for what I’m trying to do.

The activity stream items have no further interactivity such as a form, Like button, etc. I suppose I can’t rule that out in the far future…for now I’m not sure I’m using these abstractions correctly simply to update a timestamp display on an otherwise static piece of data.

Any thoughts on how to design this?

thanks!
Desmond

1 Like

Could you pass the component the event time and use a hook to periodically change the ago-time?

or if you want them synchronised, have the hook create an event handler and fire the event from the liveview periodically.

1 Like

@cmo ah, so you’re suggesting doing all the time-ago phrase management on the frontend? that would let me keep my function components, and a library like https://www.npmjs.com/package/javascript-time-ago is probably more robust than my homegrown pattern matching.

I don’t need the updates to be synchronized, in fact I would prefer they not be (I think it’s jarring when all the UI updates at once like that).

So it sounds like the answer to my question is “don’t use LiveView for dynamic formatting changes.” thanks!

You can use send_update_after to implement a tick interval in live components.